Vous êtes sur la page 1sur 686

Le langage C

Apprenez rapidement et simplement les bases du langage C

Peter Aitken Bradley L. Jones dition revue et complte te par Yves Mettier

http://fribok.blogspot.com/

L E P R O G R A M M E U R

Le langage C

Peter Aitken et Bradley L. Jones


dition revue et complte par Yves Mettier

http://fribok.blogspot.com/

Pearson Education France a apport le plus grand soin la ralisation de ce livre an de vous fournir une information complte et able. Cependant, Pearson Education France nassume de responsabilits, ni pour son utilisation, ni pour les contrefaons de brevets ou atteintes aux droits de tierces personnes qui pourraient rsulter de cette utilisation. Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle. Pearson Education France ne pourra en aucun cas tre tenu pour responsable des prjudices ou dommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou programmes. Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs propritaires respectifs.
Publi par Pearson Education France 47 bis, rue des Vinaigriers 75010 PARIS Tl. : 01 72 74 90 00 Mise en pages : TyPAO ISBN : 978-2-7440-4085-6 Copyright 2009 Pearson Education France Tous droits rservs Titre original : Teach Yourself C in 21 Days, Fourth Edition Traduit de lamricain par : Christine Eberhardt, Emmanuel Simonin et Jrme Duclos Nouvelle dition franaise revue, corrige et complte par Yves Mettier ISBN original : 0-672-31069-4 Copyright 1997 Sams Publishing All rights reserved. Sams Publishing 800 East 96th Street Indianapolis, Indiana 46290 USA
Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans le respect des modalits prvues larticle L. 122-10 dudit code. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher.

http://fribok.blogspot.com/

Sommaire

Introduction ........................................... 1. Comment dmarrer .......................... 2. Structure dun programme C .......... 3. Constantes et variables numriques 4. Instructions, expressions et oprateurs 5. Les fonctions ...................................... 6. Les instructions de contrle ............. 7. Les principes de base des entres/sorties ............................. 8. Utilisation des tableaux numriques 9. Les pointeurs ..................................... 10. Caractres et chanes ...................... 11. Les structures ..................................

1 7 25 37 53 87 111 133 159 177 201 223

12. La porte des variables .................. 13. Les instructions de contrle (suite) 14. Travailler avec lcran et le clavier 15. Retour sur les pointeurs ................ 16. Utilisation de chiers sur disque .... 17. Manipulation de chanes de caractres ..................................... 18. Retour sur les fonctions ................. 19. Exploration de la bibliothque des fonctions ...................................... 20. La mmoire ...................................... 21. Utilisation avance du compilateur Annexes .................................................. Index .......................................................

257 279 303 343 391 433 467 483 511 537 565 681

http://fribok.blogspot.com/

Table des matires

Prface ldition franaise 2008 ........ Ce que cette nouvelle dition apporte La programmation en C aujourdhui .. La programmation systme et rseau . Remerciements ................................... Introduction ........................................... Caractristiques de ce livre ................ O trouver le code prsent dans ce livre Conventions ........................................

XI XI XIV XVI XVI 1 1 4 4 5 5 7 8 8 9 10 14 18

Q & R ................................................. Atelier ................................................ Exemple pratique 1. Lecture au clavier et afchage lcran ........................ CHAPITRE 2. Structure dun programme C Exemple de programme ..................... Structure du programme .................... tude de la structure dun programme Rsum ............................................... Q & R ................................................. Atelier ................................................ CHAPITRE 3. Constantes et variables numriques ....................................... La mmoire ........................................ Les variables ...................................... Les types de variables numriques ..... Les constantes .................................... Rsum ............................................... Q & R ................................................. Atelier ................................................

18 19 23 25 26 27 31 33 33 34 37 38 39 40 45 50 50 51

Tour dhorizon de la Partie I


Ce que vous allez apprendre .............. CHAPITRE 1. Comment dmarrer ......... Bref historique du langage C ............. Pourquoi utiliser le langage C ? ......... Avant de programmer ......................... Cycle de dveloppement du programme Votre premier programme C .............. Rsum ...............................................

http://fribok.blogspot.com/

CHAPITRE 4. Instructions, expressions et oprateurs ..................................... Les instructions .................................. Les expressions .................................. Les oprateurs .................................... Linstruction if .................................... valuation des expressions de comparaison .................................. Les oprateurs logiques ...................... Les valeurs VRAI/FAUX ................... Rorganisation de la hirarchie des oprateurs ...................................... Rsum ............................................... Q & R ................................................. Atelier ................................................ Exemple pratique 2. Le nombre mystre .............................................. CHAPITRE 5. Les fonctions .................... Quest-ce quune fonction ? ............... Fonctionnement .................................. Les fonctions et la programmation structure ............................................ criture dune fonction ...................... Passage darguments une fonction .. Appel dune fonction ......................... Le placement des fonctions ................ Rsum ............................................... Q & R ................................................. Atelier ................................................

53 54 56 57 65 70 73 74 79 80 80 81 85 87 88 90 92 94 102 103 106 107 107 108

Lecture de donnes numriques avec scanf() ......................................... Rsum ............................................... Q & R .................................................. Atelier ................................................. Rvision de la Partie I ............................

142 147 147 147 151 157 157 159 160 165 173 173 174 177 178 179 183 184 190 191 192 196 197 197 199 201 202 202 205 206 206 211 213 217 218 219

Tour dhorizon de la Partie II


Ce que vous allez apprendre ............... CHAPITRE 8. Utilisation des tableaux numriques ........................................ Dnition ............................................ Le nom et la dclaration des tableaux Rsum ............................................... Q & R .................................................. Atelier ................................................. CHAPITRE 9. Les pointeurs .................... Dnition ............................................ Pointeurs et variables simples ............. Pointeurs et types de variables ............ Pointeurs et tableaux ........................... Prcautions demploi .......................... Pointeurs et index de tableaux ............ Passer des tableaux une fonction ..... Rsum ............................................... Q & R .................................................. Atelier ................................................. Exemple pratique 3. Une pause ............ CHAPITRE 10. Caractres et chanes ..... Le type de donne char ....................... Les variables caractre ........................ Les chanes ......................................... Chanes et pointeurs ............................ Les chanes sans tableaux ................... Afchage de chanes et de caractres . Lecture des chanes de caractres ....... Rsum ............................................... Q & R .................................................. Atelier .................................................

CHAPITRE 6. Les instructions de contrle 111 Les tableaux ....................................... Contrle de lexcution du programme Les boucles imbriques ...................... Rsum ............................................... Q & R ................................................. Atelier ................................................ CHAPITRE 7. Les principes de base des entres/sorties ............................. Afcher des informations lcran .... 112 112 129 130 130 131 133 134

http://fribok.blogspot.com/

CHAPITRE 11. Les structures ................. Les structures simples ......................... Les structures plus complexes ............ Tableaux de structures ........................ Initialisation des structures ................. Structures et pointeurs ........................ Les unions ........................................... Structures et typedef ........................... Rsum ............................................... Q & R .................................................. Atelier ................................................. CHAPITRE 12. La porte des variables . Dnition de la porte ........................ Les variables externes ......................... Les variables locales ........................... Les variables locales et la fonction main() .................................................. Choix de la classe de stockage ........... Variables locales et blocs .................... Rsum ............................................... Q & R .................................................. Atelier .................................................

223 224 227 232 235 238 246 252 253 253 253 257 258 260 262 267 267 268 269 269 270

Les entres au clavier ......................... Les sorties cran ................................. Redirection des entres/sorties ........... Quand utiliser fprintf() ....................... Rsum ............................................... Q & R ................................................. Atelier .................................................

307 324 334 336 337 337 338 341 341 343 344 345 353 360 370 386 386 387 391 392 392 392 393 397 408 409 414 417 422 424 425 425

Tour dhorizon de la Partie III


Quallez-vous voir maintenant ? ........ CHAPITRE 15. Retour sur les pointeurs Pointeur vers un pointeur ................... Pointeurs et tableaux plusieurs dimensions .......................................... Tableaux de pointeurs ......................... Pointeurs vers des fonctions ............... Les listes chanes .............................. Rsum ............................................... Q & R ................................................. Atelier ................................................. CHAPITRE 16. Utilisation de chiers sur disque .......................................... Flots et chiers sur disque .................. Types de chiers sur disque ................ Noms de chiers ................................. Ouverture dun chier ........................ criture et lecture dun chier de donnes .......................................... Entres-sorties tamponnes ................ Accs squentiel oppos accs direct Dtection de la n d un chier .......... Fonctions de gestion de chier ........... Emploi de chiers temporaires ........... Rsum ............................................... Q & R ................................................. Atelier .................................................

Exemple pratique 4. Les messages secrets 275 CHAPITRE 13. Les instructions de contrle (suite) .............................. Fin de boucle prmature ................... Linstruction goto ................................ Les boucles innies ............................ Linstruction switch ............................ Sortir du programme ........................... Introduction de commandes systme dans un programme ............................ Rsum ............................................... Q & R .................................................. Atelier ................................................. CHAPITRE 14. Travailler avec lcran et le clavier ......................................... Les ots du C ...................................... Les fonctions dentres/sorties ........... 279 280 284 286 289 297 298 300 300 300 303 304 306

http://fribok.blogspot.com/

Exemple pratique 5. Comptage des caractres ..................................... CHAPITRE 17. Manipulation de chanes de caractres ..................................... Longueur dune chane ...................... Copie de chanes de caractres .......... Concatnation de chanes de caractres Comparaison de deux chanes de caractres ....................................... Recherche dans une chane de caractres ....................................... Conversions de chanes ...................... Fonctions de conversion dune chane de caractres en nombre ..................... Fonctions de test de caractres ........... Rsum ............................................... Q & R ................................................. Atelier ................................................ CHAPITRE 18. Retour sur les fonctions Passage de pointeurs une fonction .. Les pointeurs de type void ................. Fonctions avec un nombre variable darguments ........................................ Fonctions renvoyant un pointeur ........ Rsum ............................................... Q & R ................................................. Atelier ................................................

429 433 434 435 440 444 447 454 455 460 464 464 464 467 468 472 475 478 480 480 481

Exemple pratique 6. Calcul des versements dun prt ............................................ 509 CHAPITRE 20. La mmoire ..................... Conversions de types .......................... Allocation despace mmoire ............. Manipulation de blocs de mmoire .... Oprations sur les bits ......................... Rsum ............................................... Q & R .................................................. Atelier ................................................. CHAPITRE 21. Utilisation avance du compilateur .................................. Utilisation de plusieurs chiers sources ................................................ Le prprocesseur C ............................. Macros prdnies .............................. Les arguments de la ligne de commande ...................................... Rsum ............................................... Q & R .................................................. Atelier ................................................. Rvision de la Partie III ........................ 511 512 516 524 526 532 532 533 537 538 543 553 554 556 556 557 559 565 565 571

Annexes
ANNEXE A. Charte des caractres ASCII ANNEXE B. Mots rservs ....................... ANNEXE C. Travailler avec les nombres binaires et hexadcimaux ................................ Le systme des nombres dcimaux .... Le systme binaire .............................. Le systme hexadcimal ..................... ANNEXE D. Portabilit du langage ....... Garantir la compatibilit ANSI ........... Renoncer au standard ANSI ............... Les variables numriques portables .... Unions et structures portables .............

CHAPITRE 19. Exploration de la bibliothque des fonctions ..................................... 483 Les fonctions mathmatiques ............. Prenons le temps... ............................. Fonctions de traitement derreur ........ Le chier den-tte errno.h ................ Recherche et tri .................................. Rsum ............................................... Q & R ................................................. Atelier ................................................ 484 487 493 495 498 505 505 506

575 576 576 576 579 583 584 584 597

http://fribok.blogspot.com/

Rsum ............................................... Q & R .................................................. Atelier ................................................. ANNEXE E. Fonctions C courantes ........ ANNEXE F. Bibliothques de fonctions .... Les bibliothques de fonctions ........... Structures de donnes ......................... Interfaces utilisateur ............................ Jeux et multimdia .............................. Programmation rseau ........................ Bases de donnes et annuaires ............ ANNEXE G. Les Logiciels libres ............. Licence et copyright ........................... Quest-ce quun logiciel libre ? .......... Diffrences entre les diverses licences Diffuser un logiciel libre ..................... Traduction franaise de la licence GPL version 2 .............................................. ANNEXE H. Rponses .............................. Rponses aux questions du Chapitre 1

603 603 604 607 615 616 617 618 619 620 621 623 624 624 626 627 628 635 636

Rponses aux questions du Chapitre 2 Rponses aux questions du Chapitre 3 Rponses aux questions du Chapitre 4 Rponses aux questions du Chapitre 5 Rponses aux questions du Chapitre 6 Rponses aux questions du Chapitre 7 Rponses aux questions du Chapitre 8 Rponses aux questions du Chapitre 9 Rponses aux questions du Chapitre 10 Rponses aux questions du Chapitre 11 Rponses aux questions du Chapitre 12 Rponses aux questions du Chapitre 13 Rponses aux questions du Chapitre 14 Rponses aux questions du Chapitre 15 Rponses aux questions du Chapitre 16 Rponses aux questions du Chapitre 17 Rponses aux questions du Chapitre 18 Rponses aux questions du Chapitre 19 Rponses aux questions du Chapitre 20 Rponses aux questions du Chapitre 21 Index .......................................................

637 639 641 643 647 648 653 657 659 663 665 669 670 671 673 674 675 676 677 679 681

http://fribok.blogspot.com/

Prface ldition franaise 2008

Le langage C est un langage ancien qui date des annes 1970 et est toujours dactualit. Cest un langage relativement simple apprendre et mettre en uvre et un langage puissant, si puissant que, quarante ans aprs sa cration, il reste la rfrence en matire de programmation. Cet ouvrage, que nous vous remercions davoir achet, vous prsente le C en vingt et un chapitres, ce qui devrait vous permettre, comme lindique le titre original Teaching yourself in 21 days, dapprendre ce langage en trois semaines raison de un chapitre par jour. la n de ce livre, vous serez apte raliser de petits programmes et comprendre le code des plus gros. Mais, laide de bibliothques de fonctions existantes, vous pourrez crer vos interfaces graphiques, communiquer avec dautres programmes sur Internet, raliser des jeux ou traiter des donnes issues des bases de donnes.

Ce que cette nouvelle dition apporte


Cette nouvelle dition a pour origine la traduction en franais de Teaching yourself in 21 days, qui date de 1995 pour la version originale et de 1997 pour la traduction. Souvenezvous, en 1995, Microsoft publiait le lgendaire systme Windows 95. Mais MS-DOS occupait encore bon nombre dordinateurs. La socit Apple tait au contraire en grande difcult (au point de changer de PDG dbut 1996). Le monde Unix tait rserv aux professionnels. Quant Linux, il navait que quatre ans et nintressait que les amateurs, dont un grand nombre dtudiants. En 1995, les programmeurs en C suivaient encore pour beaucoup la norme ANSI alors que la norme ISO C89 tait parue six ans auparavant. Mais elle ntait pas sufsamment supporte pour tre considre comme le nouveau standard du C.

http://fribok.blogspot.com/

Les ordinateurs taient encore sur 16 bits et les nouveaux Pentium sur 32 bits venaient dapparatre. En 2008, les choses ont chang. MS-DOS a disparu et les versions de Microsoft Windows se sont succd, gagnant en stabilit. Mais, surtout, Unix est revenu en force avec le succs inattendu de GNU/Linux, la nouvelle version de Mac OS X, dont la base, appele Darwin, nest rien dautre quun Unix, et dans le milieu professionnel lamlioration des systmes Unix existants. Le succs des logiciels libres a permis tous de disposer de systmes dexploitation libres et gratuits et, pour les programmeurs, de dvelopper de plus en plus de fonctionnalits. Les ordinateurs 32 bits sont de rigueur et le 64 bits commence apparatre chez les particuliers. En une dizaine dannes, le C semble tre le seul ne pas avoir boug et lon pourrait se prendre penser que cest un tmoin des annes 1970. Mais, dtrompez-vous, ce qui devait tre une simple relecture et mise jour de cet ouvrage sest rvl un vritable travail dadaptation. Le C a peu chang, mais les ordinateurs ont volu, les hommes aussi. Voici ce que cette nouvelle dition apporte.

Linux et MS-DOS, 64, 32 et 16 bits


La plupart des rfrences MS-DOS ont t remplaces et adaptes Linux. Tous deux ont cette similarit de disposer dune interface en ligne de commande. de rares exceptions prs, ce qui tait valable pour MS-DOS lest pour Linux dans ce livre. En revanche, le passage de 16 bits 32 bits a t plus dlicat. Cela a concern dune part les entiers de type int et dautre part les pointeurs. Diffrencier un int qui faisait autrefois 2 octets et un float de 4 octets devient sans intrt. Il a fallu adapter les exemples soit en remplaant les int en short, qui ont toujours une taille de 2 octets, soit en remplaant les float par des double. Quant aux pointeurs, ils nous ont oblig refaire de nombreuses gures.

Considrations de scurit
Les aspects de scurit informatique sont apparus dans les annes 1990 avec Internet, qui a dmultipli le nombre de virus et autres vers informatiques. Internet a galement permis aux pirates informatiques de pntrer plus facilement les ordinateurs en sy connectant distance et en protant de failles des programmes. Dans ce livre, la plus agrante tait lutilisation massive de la fonction gets(), qui permet de lire une ligne au clavier. Trs simple demploi, elle est trs prise des programmeurs dbutants. Cependant, cette instruction est elle seule une faille de scurit. En effet, elle neffectue aucun contrle sur la longueur de la chane de caractres que lutilisateur lui donne. Sil est mal intentionn, il peut envoyer plus de caractres que le programme ne peut en accepter, ce qui peut entraner un plantage de celui-ci, voire pire. Vous devez retenir deux choses de cela :

Nutilisez JAMAIS la fonction gets(). Vous pouvez utiliser fgets() la place.

http://fribok.blogspot.com/

fgets() ntant pas tout fait quivalente gets(), et pour ne pas avoir rcrire tous les exemples du livre, nous avons crit une autre fonction, lire clavier(), quasi quivalente gets(). Vous trouverez son code dans lexemple pratique 1. Vous devrez recopier la dnition de cette fonction dans tous les exemples qui y font appel.

Dans le mme ordre desprit, la fonction scanf() peut, mal employe, faire apparatre la mme faille de scurit que gets(). Si vous utilisez scanf(), ne mettez jamais "%s" dans sa chane de format. Indiquez toujours une longueur maximale de chane, comme "%10s" pour un maximum de 10 caractres. Pour rsumer cette section trs importante, NUTILISEZ JAMAIS gets() ET NE METTEZ JAMAIS "%s" DANS LE FORMAT DE scanf().

Conventions de codage
Une dernire modication gnrique du code a consist faire terminer tous les programmes par un appel exit(EXIT SUCCESS) ou exit(EXIT FAILURE) selon le cas. Cela implique linclusion du chier den-ttes stdlib.h qui a t ajout au dbut des exemples lorsquil ny tait pas dj. Nous nous trouvons ici dans les conventions de codage car vous trouverez souvent return 0 ou exit(0) la place de exit(EXIT SUCCESS) et la diffrence est faible. Nous recommandons en fait lutilisation des constantes prdnies lorsquelles existent et que cela est possible. Il existe dautres conventions de codage que nous navons pas souhait appliquer ici car ce sont plus des habitudes (des bonnes) que des rgles de programmation. Ainsi, si vous crivez un test de comparaison entre une variable et un nombre, par exemple x == 3, il est prfrable dcrire 3 == x. En effet, dans ce cas, si vous oubliez un signe gal, la premire expression attribue la valeur 3 la variable x alors que la seconde est tout simplement invalide (il est impossible daffecter x 3). Dans le premier cas, vous introduisez un bogue alors que, dans le second cas, le compilateur verra lerreur et ne manquera pas de vous la signaler. Pour dautres conventions de codage, nous vous recommandons la lecture des GNU Coding Standards, disponible ladresse http://www.gnu.org/prep/standards/.

Gestion de la mmoire : faites ce que je dis, pas ce que je fais


Une modication importante qui na pas t faite dans ce livre concerne les allocations de mmoire (avec malloc(), par exemple). Celle-ci est en effet rarement libre dans les exemples (avec free()). Nous avons hsit reprendre les exemples mais leur lisibilit la emport sur la rigueur pour faciliter la comprhension. Dans lanalyse, il est rappel que vous devez librer la mmoire. En dautres termes, faites ce que je dis, pas ce que je fais. Dans vos programmes, cela est essentiel car, si la mmoire nest plus

http://fribok.blogspot.com/

limite 640 kilo-octets comme au temps de MS-DOS, elle nest toujours pas extensible et, surtout, elle est maintenant partage entre les diverses applications qui tournent en parallle votre programme sur votre ordinateur.

La programmation en C aujourdhui
Le langage C a peu volu. Depuis les annes 1970 sont sorties les normes C89, largement supporte par les compilateurs, et C99, plus rcente. Mais, depuis dix ans, le monde a chang. Dautres normes sont sorties. Dautres besoins sont apparus. Des outils et des bibliothques de fonctions ont t crits.

Les normes
Les normes C89 et C99 sont assez proches de la norme ANSI dorigine. Ces normes cadrent le langage C. Mais il fallait galement normer les systmes dexploitation. En effet, cela peut sembler agrable dentendre dire que le langage C est trs portable et existe sur la plupart des plates-formes. Mais quoi bon cette portabilit si vos programmes fonctionnent de faon diffrente sur chacune delles. Pour cela, une autre norme a t cre pour les systmes dexploitation. Il sagit de la norme POSIX. La plupart des systmes dexploitation grand public respectent cette norme. Cest le cas entre autres de Windows NT et Vista ( condition dactiver certaines fonctionnalits optionnelles), de GNU/Linux et de Mac OS X. Il existe galement dautres normes comme BSD (BSD4.3 ou BSD4.4, par exemple), SVr4 (System V Release 4). Ces normes sont galement rpandues et vous pouvez vous y er.

Les besoins
Les besoins en termes de programmation ont volu par rapport il y a quelques annes. Avec lessor des logiciels libres et laugmentation du nombre de fonctionnalits inhrentes aux systmes dexploitation, les nombreux petits utilitaires que les programmeurs dveloppaient pendant leur temps libre sont intgrs et nont plus besoin dtre crits. Par exemple, rares sont ceux qui vont crire un nime explorateur de chiers. Les technologies voluent aussi. Par exemple, il tait autrefois simple dimprimer sur une imprimante matricielle branche au port parallle de votre ordinateur. Aujourdhui, limprimante est relie au port USB quand elle nest pas connecte un serveur dimpression. De plus, lamlioration de nos crans et laugmentation de leur taille ne ncessitent plus forcment dimprimer autant. Nous lisons de plus en plus nos documents en ligne. Ce livre a d voluer avec nos besoins. Ainsi, limpression des documents a t supprime car, pour imprimer un simple texte, vous utiliserez les fonctionnalits de redirection de la

http://fribok.blogspot.com/

ligne de commande. Dans les cas plus complexes o il sagit de mettre en page du texte et des images, nous sortons du cadre de ce livre.

Les outils
Dans les annes 1970 et peut-tre encore un peu dans les annes 1990, la programmation en C tait assez limite par la norme ANSI. Vous deviez ensuite utiliser des bibliothques de fonctions gnralement commerciales et payantes pour utiliser leurs fonctionnalits et arriver vos ns. Lessor des logiciels libres, nouveau, a permis aux dveloppeurs disoler leurs fonctions gnriques dans des bibliothques de fonctions et de les diffuser pour une utilisation libre. Alors quautrefois il tait peine pensable dembarquer une fonctionnalit de compression de donnes dans votre programme, cela est aujourdhui tout fait naturel, laide de la bibliothque adquate (par exemple zlib), de compresser en quelques lignes de code. De la mme faon, les cours et livres dalgorithmie prsentaient un grand intrt pour organiser les donnes dans des structures optimises pour leur traitement. Aujourdhui, des bibliothques ddies dmocratisent certains algorithmes, mme volus. Par exemple, utiliser une table de hachage ncessite quelques lignes de code avec la bibliothque glib alors que cela se comptait en centaines de lignes lorsquil fallait tout faire. Bien que tout cela sorte du cadre de ce livre, nous vous prsentons en annexe quelques bibliothques qui vous seront bien utiles pour continuer programmer en C au-del de ce que ce livre vous aura appris. Un des outils les plus importants si ce nest le plus important en programmation en C est le compilateur. En loccurrence, le projet GNU a dvelopp le sien, GCC (initialement GNU C Compiler et aujourdhui renomm en GNU Compilers Collection). Ce compilateur, qui est celui par dfaut sur Linux, a t port sur de nombreuses architectures dont Windows et Mac OS X, parfois tel quel, parfois en sintgrant des suites logicielles comme la suite XCode chez Apple ou lenvironnement de dveloppement intgr (EDI) WxDev-C++ Grce lui, vous disposez dun compilateur libre et gratuit sur denombreuses platesformes. Nous avons donc d faire voluer ce livre pour le prendre encompte comme, a priori, votre compilateur alors que, dans ldition originale, il sagissait de Turbo C (Borland) ou de Visual C++ (Microsoft). Enn, dans certains cas, il existe mme des outils pour nous faciliter certaines tches. Nous citerons par exemple les autotools (autoconf, automake) pour automatiser la compilation et la distribution de vos programmes en simpliant parfois des problmes de portabilit qui pourraient se poser. Nous citerons galement les outils dinternationalisation comme gettext, qui vous gnre du code et des chiers pour simplier la tche de traduction, aussi bien au programmeur, qui aura peu de travail pour permettre la traduction de son programme, quau traducteur, qui naura plus besoin de comptences pousses en programmation pour traduire.

http://fribok.blogspot.com/

La programmation systme et rseau


Deux des domaines de prdilection du langage C sont la programmation systme et rseau. un haut niveau, il est prfrable dutiliser des bibliothques qui vous facilitent la tche. Vous trouverez le nom de certaines de ces bibliothques en annexe. Cependant, un niveau plus bas, le langage C et la bibliothque standard libc fournissent un jeu de fonctions assez important. Vous pouvez par exemple parallliser lexcution de certaines parties de votre code. Vous pouvez galement crer un programme rsident (autrement appel dmon), un serveur ou un client pour se connecter au serveur, ragir des signaux (comme lappui sur les touches Ctrl+C), partager de la mmoire entre plusieurs programmes... Ce sujet est un sujet part entire et nous, auteurs et relecteur, navons pas souhait le traiter de manire approfondie dans cet ouvrage et encore moins le survoler. Si ce domaine vous intresse, nous vous conseillons de chercher sur Internet un des nombreux tutoriels ou sites de documentation sur ce sujet ou dacqurir un des quelques livres en franais qui en parlent. Nous citerons en particulier Programmation Linux en pratique (CampusPress, 2007) dArnold Robbins et C en action (OReilly, 2005) dYves Mettier, relecteur de cet ouvrage.

Remerciements
Ayant effectu un grand travail de relecture et de mise jour de cet ouvrage, je voudrais remercier Patricia Moncorg (Pearson Education) de mavoir propos de le faire, ainsi que ma famille pour mavoir soutenu, en particulier Anabella et notre petit Matthieu. Yves Mettier Auteur du Livre de recettes C en action (OReilly, 2005) et du Guide de survie Langage C (Pearson, 2007)

http://fribok.blogspot.com/

Introduction

Ce livre a t conu pour que vous matrisiez le langage C la n des vingt et un chapitres. Malgr la concurrence de langages plus rcents tels que Java ou C++, le langage C reste un bon choix pour dbuter en programmation. Vous dcouvrirez pourquoi vous avez eu raison de le choisir au Chapitre 1. Cet ouvrage prsente le langage C de la manire le plus logique possible. Votre progression en sera dautant plus facilite. Nous avons conu ce livre pour vous permettre daborder les chapitres raison de un par jour. Nous avons suppos que vous navez aucune exprience de la programmation. Bien sr, si vous avez dj utilis un autre langage, comme le basic, vous apprendrez plus vite. Uniquement consacr ltude du langage C, ce manuel sapplique tout type dordinateur ou de compilateur.

Caractristiques de ce livre
Ce manuel a adopt un certain nombre de conventions pour vous aider reconnatre des types dinformations spciques. Les paragraphes "Syntaxe" apportent tous les dtails ncessaires lutilisation dune commande ou dun concept particulier. Leurs explications sont illustres par des exemples. Les lignes qui suivent donnent un aperu de ce type de paragraphe. (Nous aborderons ces notions ds le Chapitre 1 !)

Syntaxe de la fonction printf()


#include <stdio.h> printf( chane-format [, arguments,...]);

http://fribok.blogspot.com/

printf() est une fonction qui peut recevoir des arguments. Ceux-ci doivent correspondre en nombre et en type aux spcications de conversion contenues dans la chane format. printf() envoie les informations mises en forme vers la sortie standard (lcran). Pour quun programme puisse appeler cette fonction, le chier standard dentres/sorties stdio.h doit avoir t inclus. La chane-format est requise mais les arguments sont facultatifs. Elle peut contenir des ordres de contrle. Voici quelques exemples dappels de la fonction printf(): Exemple 1 : code
#include <stdio.h> int main() { printf("voici un exemple de message!"); }

Exemple 1 : rsultat
voici un exemple de message!

Exemple 2 : code
printf("ceci affiche un caractre,%c\nun nombre,%d\nun nombre virgule \ flottante,%f", z, 123, 456.789 );

Exemple 2 : rsultat
ceci affiche un caractre, z un nombre, 123 un nombre virgule flottante, 456.789

Les rubriques "Conseils" sont une autre caractristique de ce livre. Elles mettent laccent sur ce que vous pouvez faire et sur ce que vous devrez absolument viter de faire.
eils Cons

faire Lire la n de ce chapitre. Elle vous donne les dtails de la partie situe la n de chaque chapitre. ne pas faire Sauter les questions du quiz ou les exercices. Si vous pouvez rpondre aux questions du contrle, vous tes prt poursuivre votre tude.

http://fribok.blogspot.com/

Vous rencontrerez galement des rubriques exposant des astuces, des infos, et des mises en garde. Les astuces vous donnent des raccourcis et des techniques de travail trs utiles.

ce Astu

Info

Ces rubriques fournissent des complments sur le concept C trait.

ntion Atte

Ces avertissements signalent les piges les plus courants.

De nombreux exemples de programmes sont fournis tout au long de ce livre pour illustrer les caractristiques et les concepts du C. Ces exemples se composent de trois parties : le programme lui-mme, les donnes lui transmettre et la sortie quil gnre, puis une analyse ligne par ligne de son fonctionnement. Un paragraphe Q&R clt chaque chapitre avec les rponses aux questions les plus courantes. Ce paragraphe est suivi dun atelier qui propose un quiz et des exercices portant sur les concepts du chapitre. Vous pourrez contrler la pertinence de vos rponses dans lAnnexe G. Quoi quil en soit, vous ne deviendrez pas un programmeur en langage C simplement en lisant ce livre. Ce nest quen programmant quon devient programmeur. Chaque srie de questions est suivie dune batterie dexercices. Nous vous recommandons de les faire. Crer du code est la meilleure faon de progresser. Dans les exercices intituls "CHERCHEZ LERREUR", vous devrez retrouver les erreurs que nous avons glisses dans le code et les rectier comme vous aurez le faire avec vos propres programmes. Si votre recherche est infructueuse, ces rponses sont fournies en Annexe G. Plus vous avancerez dans ce livre, plus les rponses de certains exercices deviendront longues. Dautres encore peuvent avoir de multiples solutions. Cest pour ces raisons que vous ne retrouverez pas toutes les solutions des derniers chapitres en Annexe G.

Amliorations
Rien nest parfait, mais on peut approcher de la perfection. Cette dition est la quatrime et nous nous sommes efforcs de vous prsenter un code compatible cent pour cent avec le plus grand nombre possible de compilateurs C. Plusieurs contrles ont t raliss pour assurer ce livre le meilleur niveau technique. Ces contrles sajoutent ceux des auteurs et aux transformations qui ont suivi les suggestions des lecteurs des trois ditions prcdentes.

http://fribok.blogspot.com/

Info

Le code source prsent dans ce livre a t test et compil sur les platesformes suivantes : DOS, Windows, System 7.x (Macintosh), UNIX et OS/2. Les lecteurs des ditions prcdentes ont galement utilis ce code sur toutes les plates-formes supportant le C.

Les sections "Exemple pratique" sont une nouveaut de cette dition. Elles sont au nombre de six et prsentent un programme C court qui accomplit une tche utile ou amusante. Lobjectif de ces programmes est dillustrer des techniques de programmation C. Vous pouvez saisir ces programmes et les excuter, puis manipuler ventuellement le code pour trouver dautres applications. Ces sections sont destines lexprimentation. Nous esprons que vous les apprcierez.

O trouver le code prsent dans ce livre


Vous trouverez le code source des principaux exemples de ce livre sur le site de Pearson ducation France : www.pearsoneducation.fr.

Conventions
Ce livre utilise diffrentes polices de caractres qui vous aideront diffrencier le code C de ses commentaires, et qui mettront en valeur les concepts importants. Le code C est imprim avec une police de caractres particulire largeur fixe. Les donnes entres par lutilisateur en rponse aux messages des programmes sont reprsentes avec cette mme police en caractres gras. Les termes qui reprsentent ce que vous devrez effectivement saisir dans le code C sont imprims en largeur fixe et en italique. Les termes nouveaux ou importants sont imprims en italique.

http://fribok.blogspot.com/

Tour dhorizon de la Partie I

Avant de commencer votre apprentissage du langage C, un compilateur et un diteur sont ncessaires. Si vous navez ni lun ni lautre, vous pouvez quand mme utiliser ce livre mais la valeur de son enseignement en sera diminue. La meilleure faon dapprendre un langage de programmation est de crer et lancer de nombreux programmes. Les exemples donns dans ce livre offrent un bon support pour les dnitions et exercices. Chaque chapitre se termine par un atelier constitu dun quiz et de quelques exercices portant sur les sujets tudis. Les rponses et solutions compltes des premiers chapitres se trouvent dans lAnnexe G. Il na pas t possible de prvoir toutes les rponses pour les derniers chapitres car il existe un grand nombre de solutions. Nous vous recommandons de tirer le meilleur parti de ces ateliers et de contrler vos rponses.

Ce que vous allez apprendre


Cette premire partie aborde les notions de base du C. Les Chapitres 1 et 2 vous apprendront crer un programme C et en reconnatre les lments de base. Le Chapitre 3 dnit les diffrents types de variables C. Le Chapitre 4 introduit les instructions et expressions dun programme pour obtenir de nouvelles valeurs. Il vous explique galement comment introduire des conditions dans lexcution dun programme avec lordre IF. Le Chapitre 5 traite des fonctions du langage C et de la programmation structure. Le Chapitre 6 concerne les commandes qui permettent de

http://fribok.blogspot.com/

contrler le droulement des programmes. Enn, le Chapitre 7 vous permettra dimprimer et de dialoguer avec votre clavier ou votre cran. Ce livre sappuie sur le standard C ANSI. Cela signie que vous pouvez utiliser le compilateur C de votre choix sil respecte bien la norme ANSI.

Info

http://fribok.blogspot.com/

1
Comment dmarrer
Vous apprendrez dans ce chapitre :

Pourquoi le langage C reprsente le meilleur choix dun langage de programmation Les tapes du cycle de dveloppement dun programme Comment crire, compiler et lancer votre premier programme C Comment faire face aux messages derreurs gnrs par le compilateur et lditeur de liens

http://fribok.blogspot.com/

Bref historique du langage C


Le langage C a t cr par Dennis Ritchie aux Bell Telephone Laboratories en 1972. Il a t conu dans un dessein bien prcis : dvelopper le systme dexploitation UNIX, dj utilis sur de nombreux ordinateurs. Ds lorigine, il devait donc permettre aux programmeurs de travailler de manire productive et efcace. En raison de sa puissance et de sa souplesse, lutilisation du C sest rapidement rpandue au-del des laboratoires Bell. Les programmeurs ont commenc lutiliser pour crire toutes sortes de programmes. Rapidement, des organisations diverses ont utilis leurs propres versions du langage C, et de subtiles diffrences dimplmentation sont devenues un vritable casse-tte pour les programmeurs. En rponse ce problme, lAmerican National Standards Institute (ANSI) a form un comit en 1983 pour tablir une dnition standard du C, qui est devenu le C standard ANSI. quelques exceptions prs, les compilateurs C daujourdhui adhrent ce standard. Le nom du langage C vient de son prdcesseur qui tait appel B. Le langage B a t dvelopp par Ken Thompson qui travaillait aussi aux laboratoires Bell.

Pourquoi utiliser le langage C ?


Il existe de nombreux langages de programmation de haut niveau comme le C, le Pascal, ou le Basic. Ils sont tous excellents et conviennent pour la plupart des tches de programmation. Toutefois, les professionnels placent le langage C en tte de liste pour plusieurs raisons :

Il est souple et puissant. Ce que vous pourrez accomplir avec ce langage nest limit que par votre imagination. Vous naurez aucune contrainte. Le langage C est utilis pour des projets aussi varis que des systmes dexploitation, des traitements de textes, des graphiques, des tableurs ou mme des compilateurs pour dautres langages. Lorsquune nouvelle architecture (nouveau processeur, nouveau systme dexploitation...) apparat, le premier langage disponible est gnralement le C car contrairement dautres, il est facile porter. De plus, un compilateur C est souvent disponible sur les ordinateurs ( lexception de Windows malheureusement), ce qui nest pas le cas pour les autres langages. Avec la norme ANSI, le C est devenu un langage portable. Cela signie quun programme C crit pour un type dordinateur (un PC IBM, par exemple) peut tre compil pour tourner sur un autre systme (comme un DEC VAX) avec trs peu ou

http://fribok.blogspot.com/

aucune modication. Les rgles qui sont respecter par les compilateurs sont dcrites plus loin dans ce livre.

Le langage C contient peu de mots. Une poigne dexpressions appeles mots cls servent de bases pour llaboration des fonctions. On pourrait penser, tort, quun langage possdant plus de mots cls (quelquefois appels mots rservs) pourrait tre plus puissant. Lorsque vous programmerez avec ce langage, vous vous apercevrez que vous pouvez raliser nimporte quelle tche. Le langage C est modulaire. Son code peut (et devrait) tre crit sous forme de sousprogrammes appels fonctions. Ces fonctions peuvent tre rutilises pour dautres applications ou programmes. Si vous passez des informations ces fonctions, vous obtenez du code rutilisable.

Comme vous pouvez le constater, le choix du C en tant que premier langage de programmation est excellent. Vous avez certainement entendu parler de C++. Ce langage sappuie sur une technique de programmation appele programmation oriente objet. C++ tait initialement une version amliore du C, savoir un C disposant de fonctions supplmentaires pour la programmation oriente objet. Le C++ est aujourdhui un langage part entire. Si vous tes amens tudier ce langage, ce que vous aurez appris du C vous aidera grandement. Un autre langage, galement bas sur C, a t lobjet dune attention toute particulire. Il sagit de Java. Si vous dcidez de vous orienter vers la programmation Java, vous dcouvrirez rapidement quil existe de nombreuses similitudes entre ces deux langages.

Avant de programmer
Vous ne pouvez rsoudre que les problmes que vous aurez identis. Il sera alors possible de btir un plan pour les corriger. Lorsque vous aurez appliqu ce plan, vous devrez tester les rsultats pour savoir si les problmes ont bien t rsolus. Cette logique sapplique de nombreux domaines, la programmation en fait partie. Voici les tapes suivre pour crer un programme en langage C (ou dans nimporte quel autre langage) : 1. Dnir les objectifs du programme. 2. Choisir les mthodes que vous voulez utiliser pour crire ce programme. 3. Crer le programme. 4. Enn, lexcuter et observer les rsultats.

http://fribok.blogspot.com/

Un exemple dobjectif (voir tape 1) serait dcrire un traitement de texte ou un programme de base de donnes. Un objectif plus simple consiste afcher votre nom sur lcran. Si vous navez pas de fonction raliser, vous navez pas besoin dun programme. Pour la deuxime tape, vous devez dnir vos besoins, la formule utiliser, et tablir un ordre de traitement des informations. Par exemple, imaginez que quelquun vous demande dcrire un programme pour calculer laire dun cercle. Ltape 1 est ralise puisque vous connaissez votre objectif : trouver la valeur de cette aire. Ltape 2 consiste dterminer quelles sont les donnes connatre pour le calcul. Si lutilisateur du programme donne le rayon du cercle, la formule pr2 vous donnera la rponse. Vous pouvez maintenant passer aux tapes 3 et 4 qui constituent le dveloppement du programme.

Cycle de dveloppement du programme


La premire tape du dveloppement dun programme est la cration du code source avec un diteur. La deuxime tape consiste compiler ce code pour obtenir un chier objet. Dans la troisime, vous transformez le code compil en chier excutable. Le lancement du programme dans la quatrime tape permet den vrier les rsultats.

Cration du code source


Le code source est une srie de commandes ou de dclarations qui indiquent lordinateur les tches que vous voulez lui faire excuter. Cest la premire tape du dveloppement et le code source est cr laide dun diteur. Voici un exemple dinstruction de code source C :
printf("Bonjour, vous!");

Cette instruction demande lordinateur dafcher le message "bonjour, vous!" lcran.

Utilisation de lditeur
La plupart des compilateurs sont livrs avec un diteur intgr qui permet de crer le code source. Consultez votre manuel pour savoir si votre compilateur en fait partie. La plupart des systmes dexploitation contiennent un programme qui peut tre utilis comme un diteur. Si vous travaillez avec UNIX, vous pouvez utiliser vi ou vim, emacs ou un bloc-notes comme gedit ou kedit. Microsoft Windows vous offre le bloc-notes.

http://fribok.blogspot.com/

Les logiciels de traitement de texte utilisent des codes spciaux pour formater leurs documents. Ces codes ne peuvent pas tre lus correctement par les autres programmes. LAmerican Standard Code for Information Interchange (ASCII) a dni un format de texte standard que nimporte quel programme, y compris le C, peut utiliser. Beaucoup de traitements de texte, comme Open-Ofce.org, Abiword, Kofce et Microsoft Word, sont capables de sauvegarder des chiers source en format ASCII (comme un chier texte plutt que comme un chier document). Pour obtenir un chier en format ASCII avec un traitement de texte, vous devez choisir loption de sauvegarde ASCII ou texte. Vous ntes pas oblig dutiliser un de ces diteurs. Il existe des programmes, que vous pouvez acheter, qui sont spcialement destins crer du code source. Citons galement les logiciels libres (et gratuits) Ajuta et Kdevelop disponibles au moins sur GNU/ Linux. Pour trouver des diteurs diffrents, vous pouvez consulter votre revendeur local, les catalogues de vente par correspondance ou encore les petites annonces des magazines de programmation. Sur votre distribution Linux, effectuez une recherche dans les packages disponibles.

ce Astu

Quand vous sauvegardez un chier source, il faut lui donner un nom. Vous pouvez choisir nimporte quel nom ou extension, mais il existe une convention : le nom du programme doit reprsenter la fonction de ce programme et .C est reconnue comme lextension approprie.

Compilation du code source


Votre ordinateur ne peut pas comprendre le code source C. Il ne peut comprendre que des instructions binaires dans ce que lon appelle du langage machine. Votre programme C doit tre transform en langage machine pour pouvoir tre excut sur votre ordinateur. Cela reprsente la deuxime tape de dveloppement du programme. Cette opration est ralise par un compilateur qui transforme votre chier code source en un chier contenant les mmes instructions en langage machine. Ce chier cr par le compilateur contient le code objet , et on lappelle chier objet. Ce livre sappuie sur le standard C ANSI. Cela signie que vous pouvez utiliser le compilateur C de votre choix sil respecte bien la norme ANSI.

Info

http://fribok.blogspot.com/

Chaque compilateur possde sa propre commande pour crer du code objet. En gnral, il faut taper la commande de lancement du compilateur suivie du nom du chier source. Voici quelques exemples de commandes destines compiler le chier source radius.c en utilisant divers compilateurs DOS/Windows :
Compilateur
Gnu gcc C Microsoft Turbo C de Borland C Borland Compilateurs C Unix

Commande gcc radius.c cl radius.c tcc radius.c bcc radius.c cc radius.c

La compilation sera simplie dans un environnement de dveloppement graphique. Dans la plupart des cas, cette opration sera ralise partir du menu ou de licne correspondante. Une fois le code compil, il sufra alors de slectionner licne en cours ou la touche du menu adquate pour excuter le programme. Pour de plus amples renseignements vous vous rfrerez au manuel de votre compilateur. Aprs cette opration, vous trouverez dans votre rpertoire courant un nouveau chier ayant le mme nom que votre chier source, mais avec lextension .o ou .obj. Cette extension sera reconnue par lditeur de liens comme celle dun chier objet.

Cration du chier excutable


Une partie du langage C est constitue dune bibliothque de fonctions contenant du code objet (ce code a dj t compil) destin des fonctions prdnies. Ces fonctions sont fournies avec votre compilateur et printf() en est un exemple. Ces fonctions ralisent des tches trs souvent ralises comme afcher des informations lcran ou lire un chier. Si votre programme les utilise, le chier objet obtenu aprs compilation doit tre complt par le code objet issu de la bibliothque de fonctions. Cette dernire tape, appele liaison, fournit le programme excutable (excutable signie que ce programme peut tre excut sur votre ordinateur). La Figure 1.1 reprsente le schma de la transformation du code source en programme excutable.

http://fribok.blogspot.com/

Figure 1.1 Le code source est transform en code objet par le compilateur puis en chier excutable par lditeur de liens.

diteur

Code source

Compilation du fichier source

Code objet

Fichiers de bibliothque

Liaison du fichier objet

Programme excutable

Fin du cycle de dveloppement


Une fois que vous avez obtenu votre chier excutable, vous pouvez lancer votre programme en saisissant son nom linvite de votre systme. Si les rsultats obtenus sont diffrents de ceux recherchs, vous devez recommencer la premire tape. Il faut identier lorigine du problme et corriger le code source. chaque transformation de ce code, il est ncessaire de recompiler le programme et de relancer lditeur de liens (linker en anglais) pour crer une version corrige du chier excutable. Rptez ces oprations jusqu ce que le programme sexcute de faon correcte. Bien que nous ayons diffrenci la compilation de la liaison, beaucoup de compilateurs excutent ces deux oprations en une seule tape. Quelle que soit la mthode utilise, ce sont bien deux actions spares.
Cycle de dveloppement tape 1 tape 2
Utilisez un diteur pour crer le code source. Par convention, ce chier doit avoir lextension .c (par exemple, monprog.c, database.c, etc.). Compilez votre programme. Si le compilateur ne rencontre pas derreur dans votre code source, vous obtenez un chier objet du mme nom que votre chier source avec une extension .obj ou .o (par exemple, monprog.c est compil en monprog.o). Si le code source contient des erreurs, le compilateur choue et vous les afche pour correction. Excutez la liaison. Si aucune erreur napparat, vous obtenez un programme excutable dans un chier du mme nom que le chier objet (avec une extension .exe sur Windows par exemple, monprog.obj devient monprog.exe). Excutez votre programme. Contrlez les rsultats obtenus et recommencez ltape 1 si des modications sont ncessaires dans le chier source.

tape 3

tape 4

http://fribok.blogspot.com/

Les tapes de dveloppement du programme sont reprsentes dans la Figure 1.2. Il faut parcourir ce cycle jusqu obtenir le rsultat recherch. Mme le meilleur programmeur ne peut simplement sasseoir et crire un programme complet sans aucune erreur ds la premire tape. Cest pourquoi il est important de matriser parfaitement ces outils : lditeur, le compilateur et lditeur de liens.
Figure 1.2 Les tapes de dveloppement dun programme C.
Dbut
dition du code source Compilation du code source

OUI

Erreurs ? NON Liaison du programme

OUI

Erreurs ? NON Excution du programme

OUI

Erreurs ? NON

Fin

Votre premier programme C


Voici un exemple qui permettra de vous familiariser avec votre compilateur. Mme si vous ne comprenez pas la syntaxe, cet exercice est l pour vous faire crire, compiler, et excuter un programme C. Ce programme sappelle hello.c, et il va afcher "Hello, world !" sur votre cran. Vous trouverez le code source de ce programme dans le Listing 1.1. Attention, vous ne devez pas ajouter les numros de ligne ni les deux points qui suivent. Nous les avons ajouts dans ce livre pour pouvoir donner la rfrence des lignes qui seront commentes.

http://fribok.blogspot.com/

Listing 1.1 : hello.c


1: #include <stdio.h> 2: 3: int main() 4: { 5:printf("Hello, World!\n"); 6:return 0; 7: }

Installez votre compilateur en suivant les instructions fournies avec le produit. Quel que soit votre systme dexploitation (Windows, Linux, etc.), assurez-vous davoir bien compris le fonctionnement du compilateur et de lditeur de votre choix. Vous pouvez maintenant suivre les tapes ci-aprs pour saisir, compiler, et excuter hello.c.

Cration et compilation de hello.c


Voici comment crer et compiler le programme hello.c : 1. Placez-vous sur le rpertoire qui contient vos programmes C et dmarrez votre diteur. Comme nous lavons mentionn prcdemment, vous pouvez utiliser lditeur de votre choix. Cependant, beaucoup de compilateurs C (comme anjuta ou Kdevelop sur Linux et visual C/C++ de Microsoft) sont livrs avec un environnement de dveloppement intgr (EDI) qui permet de crer, de compiler et deffectuer la liaison de faon trs conviviale. Consultez vos manuels pour savoir si vous possdez un tel environnement. 2. Utilisez le clavier pour saisir le code source hello.c comme indiqu dans le Listing 1.1 en appuyant sur Entre la n de chaque ligne.
ntion Atte

Les numros de ligne de notre exemple ont t ajouts pour une meilleure comprhension. Vous ne devez pas les introduire dans votre source.

3. 4. 5. 6.

Sauvegardez votre chier source sous le nom hello.c. Vriez que le chier se trouve bien dans votre rpertoire. Excutez la commande approprie pour la compilation et la liaison de hello.c. Contrlez les messages envoys par le compilateur. Si vous navez reu aucun message derreur ou warning, votre chier source est bon. Remarque : Si vous avez fait une erreur de frappe dans votre programme, comme taper prntf pour printf, le compilateur vous enverra un message comme celui-ci : Error: undefined symbols: prntf in hello.c (hello.OBJ)

7. Retournez ltape 2 si vous avez un message derreur. ditez le chier hello.c pour comparer son contenu avec Listing 1.1. Faites les corrections ncessaires puis passez ltape 3.

http://fribok.blogspot.com/

8. Votre premier programme C est maintenant prt tre excut. Si vous faites une liste de tous les chiers de votre rpertoire qui sappellent hello, vous allez voir apparatre :
hello.c qui est le fichier source que vous avez cr. hello.obj ou hello.o qui contient le code objet de hello.c. hello.exe ou tout simplement hello qui est le programme excutable, rsultat de la compilation et de la liaison.

9. Pour excuter hello ou hello.exe, entrez simplement hello. Le message "Hello, world !" apparat lcran. Flicitations ! Vous venez de crer, de compiler et dexcuter votre premier programme C.

Les erreurs de compilation


Une erreur de compilation apparat lorsque le compilateur rencontre du code source quil ne peut pas compiler. Heureusement, les compilateurs daujourdhui vous indiquent la nature et lemplacement des erreurs pour faciliter la correction du code source. Cela peut tre illustr en introduisant dlibrment une erreur dans hello.c. ditez ce chier et effacez le point-virgule la n de la ligne 5. hello.c ressemble maintenant au chier du Listing 1.2. Listing 1.2 : hello.c avec une erreur
1: #include <stdio.h> 2: 3: int main() 4: { 5:printf(Hello, World!) 6:return 0; 7: }

Sauvegardez votre chier et compilez-le. Votre compilateur va vous envoyer un message qui ressemble celui-ci :
hello.c(6): Error: ; expected

Vous pouvez remarquer que cette ligne comporte trois parties :


hello.cLe nom du fichier dans lequel se trouve lerreur (6):Le numro de la ligneo a t dtecte lerreur Error: ; expectedUn descriptif de cette erreur

Le message vous indique qu la ligne 6 de hello, le compilateur na pas trouv de pointvirgule. Cette rponse tonnante vient du fait que le point-virgule que vous avez effac ligne 5 aurait pu se trouver la ligne suivante (mme si ce nest pas une bonne mthode de

http://fribok.blogspot.com/

programmation). Ce nest quen contrlant la ligne 6 que le compilateur a constat labsence de point-virgule. Cela illustre lambigut des messages derreur des compilateurs C. Vous devrez utiliser votre connaissance du langage C pour interprter ces messages. Les erreurs sont souvent sur la ligne indique ou sur celle qui la prcde. Les messages derreur peuvent diffrer dun compilateur lautre. Dans la plupart des cas, les indications quil vous fournira vous donneront une bonne ide du problme et de son emplacement.

ce Astu

Avant de continuer notre tude, considrons un autre exemple derreur de compilation. ditez hello.c et transformez-le comme indiqu : 1. Replacez le point-virgule la n de la ligne 5. 2. Effacez les guillemets juste avant le mot Hello. Sauvegardez le chier et compilez de nouveau le programme. Le message derreur du compilateur devient :
hello.c(5): Error: undefined identifier "Hello" hello.c(7): Lexical error: unterminated string Lexical error: unterminated string Lexical error: unterminated string Fatal error: premature end of source file

Le premier message annonce effectivement une erreur en ligne 5 au mot Hello. Le message defined identifier signie que le compilateur na pas compris Hello parce quil ne se trouve pas entre guillemets. Les messages suivants, dont nous ne nous proccuperons pas pour le moment, illustrent le fait quune seule erreur dans un programme C peut quelquefois provoquer de multiples messages. Voici ce que vous devrez en retenir : si le compilateur vous envoie plusieurs messages derreur, et que vous nen trouviez quune, corrigez-la et recompilez votre programme. Cette seule correction pourrait annuler tous les messages.

Les messages derreur de lditeur de liens


Des erreurs en provenance de lditeur de liens sont relativement rares et sont gnralement dues une faute de frappe dans le nom dune fonction appartenant la bibliothque C. Dans ce cas, le message suivant apparat : Error: undefined symbols: error message, suivi du nom mal orthographi (prcd dun tiret).

http://fribok.blogspot.com/

Rsum
La lecture de ce premier chapitre vous a certainement convaincu que le choix du C comme langage de programmation est judicieux. Il offre une bonne combinaison entre puissance, portabilit et notorit. ces qualits sajoute la possibilit dvoluer vers le langage orient objet C++ ou Java. Ce chapitre a dcrit les diffrentes tapes du dveloppement dun programme C. Vous devez matriser le cycle dition-compilation-liaison-tests ainsi que les outils ncessaires chaque tape. Les erreurs sont indissociables du dveloppement dun programme. Votre compilateur les dtecte et vous envoie un message derreur qui en donne la nature et lemplacement. Ces informations permettent dditer le code source pour le corriger. Rappelez-vous cependant que ces messages ne sont pas toujours trs prcis, et quil faut utiliser votre connaissance du C pour les interprter.

Q&R
Q Si je veux donner mon programme quelquun, de quels chiers a-t-il besoin ? R Le fait que le langage C soit un langage compil est un avantage. Cela signie que lorsque votre code source est compil, vous obtenez un programme excutable qui se suft lui-mme. Pour donner Hello tous vos amis, il suft de leur donner lexcutable (hello ou hello.exe). Ils nont pas besoin du chier source hello.c, ni du chier objet hello.o ou hello.obj. Ils nont pas besoin non plus de possder un compilateur C. Nanmoins, diffuser les sources (hello.c) accompagnes dune licence libre permettra vos amis dveloppeurs damliorer Hello. Q Faut-il conserver les chiers sources (.c) et objets (.obj ou .o) aprs la cration du chier excutable ? R Si vous supprimez votre chier source, vous naurez aucune possibilit plus tard dapporter une modication votre programme. Vous devriez donc le garder. Pour ce qui concerne le chier objet, vous pouvez en obtenir une copie tout moment en recompilant le chier source. Vous navez donc pas besoin de le conserver. La plupart des environnements de dveloppement intgrs crent des chiers qui sajoutent ceux dj cits ci-avant. Vous pourrez les recrer aussi longtemps que vous serez en possession du chier source (.c).

http://fribok.blogspot.com/

Q Faut-il utiliser lditeur qui est livr avec le compilateur ? R Ce nest pas une obligation. Vous pouvez utiliser lditeur de votre choix du moment que vous sauvegardez le code source en format texte. Si votre compilateur possde un diteur, vous devriez lessayer et choisir celui qui vous convient le mieux. Jutilise moi-mme un diteur que jai achet sparment alors que tous les compilateurs que jutilise en ont un. Ces diteurs qui sont livrs avec les compilateurs sont de plus en plus performants. Certains formatent automatiquement votre code source. Dautres distinguent les diffrentes parties de votre chier source laide de couleurs diffrentes pour vous aider trouver les erreurs. Q Peut-on ignorer les messages davertissement ? R Certains de ces messages naffectent en rien lexcution de votre programme, dautres pas. Si votre compilateur vous envoie un message de warning, cela signale que quelque chose ne convient pas. Beaucoup de compilateurs vous offrent la possibilit de supprimer ce genre de message en dessous dun certain niveau. Le compilateur ne donnera que les messages les plus srieux. Vous devriez cependant consulter tous vos messages, un programme est meilleur sil ne comporte aucune erreur ou warning (le compilateur ne produit pas de programme excutable sil reste une seule erreur dans le source).

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre. Essayez de comprendre les rponses fournies dans lAnnexe G avant de passer au chapitre suivant.

Quiz
1. Donnez trois raisons pour lesquelles le C est un bon choix de langage de programmation. 2. Quel est le rle du compilateur ? 3. Quelles sont les tapes du cycle de dveloppement dun programme ? 4. Quelle commande permet de compiler le programme program.c ? 5. Votre compilateur excute-t-il la compilation et la liaison avec la mme commande ? 6. Quelle extension devriez-vous utiliser pour votre chier source C ? 7. Est-ce que lename.txt est un nom correct pour votre chier source C ?

http://fribok.blogspot.com/

8. Que faut-il faire si le programme que vous avez compil ne donne pas les rsultats escompts ? 9. Quest ce que le langage machine ? 10. Que fait lditeur de liens ?

Exercices
1. ditez le chier objet cr avec Listing 1.1. Ressemble-t-il au chier source ? (Ne sauvegardez pas ce chier lorsque vous quitterez lditeur.) 2. Entrez le programme suivant et compilez-le. Que fait-il ? (Ne saisissez pas les numros de ligne ni les deux points.)
1: #include <stdio.h> 2: 3: int rayon, aire; 4: 5: int main() 6: { 7:printf("Entrez le rayon (ex 10): "); 8:scanf("%d", &rayon); 9:aire = (3.14159 * rayon * rayon); 10:printf("\n\nAire =%d\n", aire); 11:return 0; 12: }

3. Saisissez et compilez le programme suivant. Que fait-il ?


1: #include <stdio.h> 2: 3: int x,y; 4: 5: int main() 6: { 7:for (x = 0; x < 10; x++, printf("\n")) 8:for (y = 0; y < 10; y++) 9:printf ("X"); 10: 11:return 0; 12: }

4. CHERCHEZ LERREUR : Saisissez ce programme et compilez-le. Quelles sont les lignes qui gnrent des erreurs ?
1: #include <stdio.h> 2: 3: int main(); 4: {

http://fribok.blogspot.com/

5:printf ("Regardez bien!"); 6:printf ("Vous allez trouver!"); 7:return 0; 8: }

5. CHERCHEZ LERREUR : Saisissez ce programme et compilez-le. Quelles sont les lignes qui gnrent des erreurs ?
1: #include <stdio.h> 2: 3: int main(); 4: { 5:printf ("Ce programme a vraiment"); 6:do_it("un problem!"); 7:return 0; 8: }

6. Transformez la ligne 9 de lexercice 3 comme indiqu. Recompilez et excutez le nouveau programme. Que fait-il maintenant ?
9:printf("%c", 65);

http://fribok.blogspot.com/

Exemple pratique 1

Lecture au clavier et afchage lcran


Vous trouverez, dans ce livre, plusieurs sections de ce type prsentant un programme un peu plus long que les exemples fournis dans les chapitres. Il pourra contenir des lments qui nauront pas encore t abords, mais vous aurez ainsi la possibilit de saisir un programme complet puis de lexcuter. Les programmes prsents constitueront des applications pratiques ou amusantes. Le programme perroquet de cette section, par exemple, lit une ligne au clavier et lafche. Ce programme contient dailleurs une fonction qui sera utilise tout au long de cet ouvrage : lire_clavier(). Vous devrez la recopier telle quelle dans chaque programme qui y fait appel. Prenez le temps de tester ces programmes. Modiez-les, recompilez, puis excutez-les de nouveau. Observez les rsultats ainsi obtenus. Nous nexpliquerons pas les dtails de fonctionnement au niveau du code, seulement les oprations effectues. Vous en comprendrez toutes les subtilits lorsque vous aurez parcouru tous les chapitres. Vous avez ainsi la possibilit daborder rapidement des programmes intressants.

Le premier exemple pratique


Saisissez et compilez le programme suivant, en prenant soin de ne pas introduire de fautes de frappe (vous les retrouverez sous la forme derreurs au moment de la compilation). Pour excuter ce programme, tapez perroquet. Ne soyez pas impressionn par sa longueur, vous ntes pas cens comprendre chaque ligne de code pour linstant.

http://fribok.blogspot.com/

Listing Exemple pratique 1 : perroquet.c


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: /* perroquet.c : ce programme rpte ce quil vient de lire au clavier */ #include <stdlib.h> #include <stdio.h> int lire_clavier(char *str, int taille) { int i; fgets(str, taille, stdin); str[taille-1] = \0; for(i=0; str[i]; i++) /* supprime le retour chariot */ { if(str[i] == \n) { str[i] = \0; break; } } return(i); /* Renvoie 0 si la chane est vide */ } int main() { char buffer[80]; printf("Entrez une ligne et validez avec Entre\n"); lire_clavier(buffer, sizeof(buffer)); printf("Vous avez crit : %s\n", buffer) exit(EXIT_SUCCESS); }

Le Chapitre 5 sur les fonctions, ainsi que le Chapitre 14, qui traite des entres/sorties, vous aideront comprendre le fonctionnement de ce programme.

http://fribok.blogspot.com/

2
Structure dun programme C
Un programme C est constitu de plusieurs modules de programmation ou blocs. Une grande partie de ce livre traite de ces divers lments de programme et de leur utilisation. Avant de dtailler chacun deux, nous allons tudier un programme C complet. Aujourdhui, vous allez apprendre :

Identier les blocs de programme partir dun exemple simple Reconnatre les caractristiques de chacun de ces blocs Compiler et excuter un programme de test

http://fribok.blogspot.com/

Exemple de programme
Le Listing 2.2 reprsente le code source du programme de test. Ce programme est trs simple : il donne le produit de deux nombres saisis au clavier. Nessayez pas den comprendre les dtails, ce chapitre est destin vous familiariser avec les composants dun programme C. Avant dtudier votre programme de test, vous devez savoir ce que reprsente une fonction. Cest une partie indpendante du code du programme qui effectue une certaine tche, et qui est rfrence par un nom. En introduisant ce nom dans le programme, celui-ci peut excuter le code qui lui est associ. Le programme peut transmettre des informations, appeles arguments, cette fonction qui pourra son tour lui renvoyer une valeur. Les deux types de fonctions C sont les fonctions de bibliothque, qui sont fournies avec le compilateur C, et les fonctions utilisateur, que le programmeur peut luimme crer. Nous vous rappelons que les numros de ligne inclus dans cet exemple, comme dans tous les exemples de ce livre, ne font pas partie du programme. Ne les tapez pas. Listing 2.1 : multiplier.c
1: /* Calcul du produit de deux nombres. */ 2: #include <stdio.h> 3: 4: int produit(int x, int y); 5: 6: int main() 7: { 8: int a,b,c; 9: 10: /* Lecture du premier nombre */ 11:printf("Entrez un nombre entre 1 et 100: "); 12:scanf("%d", &a); 13: 14: /* Lecture du deuxime nombre */ 15:printf("Entrez un autre nombre entre 1 et 100: "); 16:scanf("%d", &b); 17: 18: /* Calcul du produit et affichage du rsultat */ 19:c = produit(a, b); 20:printf ("\n%d fois%d =%d", a, b, c); 21: 22:return 0; 23: } 24:

http://fribok.blogspot.com/

25: /* La fonction renvoie le produit de ses deux arguments */ 26: int produit(int x, int y) 27: { 28:return (x * y); 29: } Entrez un nombre entre 1 et 100: 35 Entrez un autre nombre entre 1 et 100: 23 35 fois 23 = 805

Structure du programme
Nous allons examiner le programme prcdent ligne par ligne pour en isoler les diffrents composants.

La fonction main()
La fonction main() est le seul bloc obligatoire dun programme C. Sa forme la plus simple consiste saisir son nom, main, suivi de parenthses () vides et dune paire daccolades{}. Celles-ci renferment la partie principale du programme. Lexcution du programme dbute la premire instruction de main() et se termine avec la dernire instruction de cette fonction.

Appel dun chier #include


Linstruction dappel #include, indique au compilateur C quil doit inclure le contenu dun chier dans le programme pendant la compilation. Ce chier inclus (aussi appel chier en-tte) contient des informations destines votre programme ou au compilateur. Plusieurs de ces chiers t livrs avec votre compilateur, vous ne devez pas en modier les informations. Ils ont tous une extension .h (par exemple, stdio.h). Dans notre exemple, linstruction dappel #include signie "ajouter le contenu du chier stdio.h". Le Chapitre 21 vous donnera de plus amples informations sur ces chiers.

La dnition de variable
Une variable est un nom donn une zone mmoire. En effet, votre programme a besoin de mmoire pour stocker ses donnes en cours dexcution. En C, une variable doit tre dnie avant dtre utilise. La dnition de variable indique son nom au compilateur et le type de donnes que lon pourra y stocker. La dnition de la ligne 8 de notre exemple, int a, b, c;, dnit trois variables appeles a, b, et c qui contiendront chacune une valeur entire. Les variables et constantes numriques sont traites au Chapitre 3.

http://fribok.blogspot.com/

La dclaration de fonction
La dclaration de fonction indique au compilateur C le nom et les arguments dune fonction qui sont utiliss dans le programme. Cette dclaration doit apparatre avant lutilisation de la fonction et ne doit pas tre confondue avec la dnition de fonction qui contient les instructions propres cette fonction. Cette dclaration est facultative si la fonction peut tre dnie avant tout appel elle.

Les instructions
Les instructions constituent le travail ralis par le programme. Elles afchent les informations sur lcran, lisent les donnes saisies au clavier, effectuent les oprations mathmatiques, appellent les fonctions, lisent les chiers et accomplissent tous types doprations ncessaires un programme. Chaque instruction occupe gnralement une ligne et se termine par un point-virgule. Ce livre est consacr en grande partie lenseignement de ces diffrentes instructions.

printf ()
printf() (lignes 11, 15, et 20) est une fonction de bibliothque qui envoie des informations lcran. Elle peut afcher un message texte simple (comme en ligne 11 ou 15) ou un message accompagn de variables issues du programme (comme en ligne 20).

scanf ()
scanf() (lignes 12 et 16) est une autre fonction de bibliothque. Elle lit les donnes entres au clavier et les attribue des variables du programme. Linstruction de la ligne 19 appelle la fonction produit() et lui transmet les arguments a et b. Le programme excute alors les instructions appartenant la fonction produit() qui lui renvoie une valeur. Cette valeur est sauvegarde dans la variable c.

return
Linstruction return de la ligne 28 fait partie de la fonction produit(). Elle calcule le produit des variables x et y, puis renvoie le rsultat au programme appelant.

La dnition de fonction
Une fonction est une portion de code indpendante qui a t crite pour effectuer une certaine tche. On appelle cette fonction dans un programme en introduisant son nom dans une instruction.

http://fribok.blogspot.com/

La fonction produit(), jusqu la ligne 29, est une fonction utilisateur . Comme son nom lindique, une fonction utilisateur est crite par le programmeur pendant le dveloppement de son programme. Celle-ci est simple, elle multiplie deux valeurs et renvoie la rponse au programme qui la appele. Vous apprendrez au Chapitre 5 quune bonne programmation C est base sur une utilisation correcte de ces fonctions. En ralit, vous navez pas besoin de crer une fonction pour une tche aussi simple que la multiplication de deux nombres. Nous lavons fait pour vous donner un exemple. Le langage C possde de multiples fonctions de bibliothques qui sont fournies avec le compilateur. Ces fonctions ralisent la plupart des tches de base (comme les entres/ sorties de lcran, du clavier, et du disque) dont votre programme a besoin. Dans notre exemple, printf() et scanf() sont des fonctions de bibliothque.

Les commentaires du programme


La partie de code du programme qui commence par /* et qui se termine par */ est un commentaire. Le compilateur lignore. Vous pouvez le placer nimporte o, il na aucune inuence sur le droulement du programme. Un commentaire peut stendre sur une ou plusieurs lignes, ou sur une partie de ligne seulement. En voici trois exemples :
/* un commentaire dune ligne*/ int a, b, c; /* sur une partie de ligne*/ /* un commentaire qui stend sur plusieurs lignes */

Vous ne devez pas imbriquer des commentaires, cela provoque une erreur avec beaucoup de compilateurs :
/* /* mauvais exemple ne pas suivre */ */

Mme si certains compilateurs les acceptent, vitez-les si vous voulez conserver une bonne portabilit de votre code C. De tels commentaires peuvent aussi conduire des problmes difciles rsoudre. Beaucoup dapprentis programmeurs considrent les commentaires comme une perte de temps inutile. Cest une erreur ! Votre code peut vous sembler tout fait clair pendant que vous le dveloppez, surtout sil sagit dun programme simple. Mais sil volue dans le temps pour devenir plus complexe, vous apprcierez ces commentaires quand vous aurez le modier. Prenez lhabitude de bien documenter ce qui le ncessite, en faisant galement attention ne pas trop en mettre.

http://fribok.blogspot.com/

Info

Certains programmeurs utilisent un type de commentaire plus rcent qui est disponible avec le langage C++ ou Java : le double slash (// ). En voici deux exemples :
// cette ligneest un commentaire int x;// les commentaires dbutent aprs les deux slash

Les deux slashs signient que la n de la ligne est un commentaire. Mme si beaucoup de compilateurs les acceptent, vous devriez les viter pour conserver une bonne portabilit de votre code.
eils Cons

faire Commenter votre code source, surtout sil contient des algorithmes qui pourraient tre difciles comprendre. Vous gagnerez un temps prcieux quand vous aurez les modier. ne pas faire Formuler des commentaires inutiles. Par exemple,
/* Le programme suivant affiche "Hello, world!" sur votre cran */ printf("Hello, World! ");

Ce commentaire est inutile si vous connaissez le fonctionnement de printf(). faire Apprendre doser les commentaires dans vos programmes. Sils sont peu nombreux ou en style tlgraphique, ils ne seront pas dun grand secours. Sils sont trop longs, vous passerez plus de temps commenter qu programmer.

Les accolades
Les accolades ({}) permettent dencapsuler les lignes de programmes qui constituent chaque fonction C. On appelle bloc lensemble des instructions qui se trouvent entre ces accolades.

Comment excuter le programme


Prenez le temps de saisir, compiler, et excuter multiplier.c. Cest une bonne occasion dutiliser votre diteur et votre compilateur. Rappelez-vous les tapes du Chapitre 1 : 1. Placez-vous sur votre rpertoire de programmation. 2. Dmarrez votre diteur. 3. Saisissez le code source comme indiqu dans le Listing 2.1, sans les numros de ligne.

http://fribok.blogspot.com/

4. Sauvegardez votre programme. 5. Lancez la compilation et la liaison du programme avec les commandes correspondantes de votre compilateur. Si aucun message derreur napparat, vous pouvez excuter le programme en tapant multiplier linvite du systme. 6. Si vous obtenez un message derreur, retournez ltape 2 et corrigez votre chier source.

Remarque
Un ordinateur est prcis et rapide, mais il ne fait quexcuter des ordres. Il est parfaitement incapable de corriger la moindre erreur . Cela est valable pour votre code source C. Le compilateur chouera la moindre faute de frappe. Heureusement, mme sil ne peut pas corriger vos erreurs, il sait les reconnatre pour vous les indiquer. (Les messages du compilateur et leur interprtation sont traits dans le chapitre prcdent.)

tude de la structure dun programme


Vous connaissez maintenant la structure dun programme. tudiez le Listing 2.2 et essayez den reconnatre les diffrentes parties. Listing 2.2 : list_it.c
1: /*list_it.c Ce programme affiche du code source avec les numros de lignes. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: void display_usage(void); 6: int line; 7: 8: int main(int argc, char *argv[]) 9: { 10:char buffer[256]; 11:FILE *fp; 12: 13:if(argc < 2) 14:{ 15: display_usage(); 16: exit(EXIT_FAILURE); 17:} 18: 19:if ((fp = fopen(argv[1], "r")) == NULL) 20:{ 21: fprintf(stderr, "erreur fichier,%s!", argv[1]);

http://fribok.blogspot.com/

22: exit(EXIT_FAILURE); 23:} 24: 25:line = 1; 26: 27:while(lire_clavier(buffer, sizeof(buffer))) 28: fprintf(stdout, "%4d:\t%s", line++, buffer); 29: 30:fclose(fp); 31:exit(EXIT_SUCCESS); 32: } 33: 34: void display_usage(void) 35: { 36:fprintf(stderr, "La syntaxe est la suivante:\n\n"); 37:fprintf(stderr, "list_it filename.ext\n"); 38: } C:\>list_it list_it.c 1: /*list_it.c Ce programme affiche du code source avec les numros de lignes. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: void display_usage(void); 6: int line; 7: 8: int main(int argc, char *argv[]) 9: { 10:char buffer[256]; 11:FILE *fp; 12: 13:if(argc < 2) 14:{ 15: display_usage(); 16: exit(EXIT_FAILURE); 17:} 18: 19:if ((fp = fopen(argv[1], "r")) == NULL) 20:{ 21: fprintf(stderr, "erreur fichier,%s!", argv[1]); 22: exit(EXIT_FAILURE); 23:} 24: 25:line = 1; 26: 27:while(lire_clavier(buffer, sizeof(buffer))) 28: fprintf(stdout, "%4d:\t%s", line++, buffer); 29: 30:fclose(fp); 31:exit(EXIT_SUCCESS); 32: } 33: 34: void display_usage(void) 35: { 36:fprintf(stderr, "\nLa syntaxe est la suivante: "); 37:fprintf(stderr, "\n\nLIST_IT filename.ext\n"); 38: }

http://fribok.blogspot.com/

Analyse list_it.c ressemble print_it.c du Chapitre 1. Il permet dafcher le source du programme numrot lcran, au lieu de lenvoyer vers limprimante. Nous pouvons identier les diffrentes parties de ce programme. La fonction main() est dveloppe de la ligne 8 32. Les lignes 2 et 3 contiennent les appels du chier en-tte #include et les dnitions de variables sont en lignes 6, 10 et 11. Nous trouvons la dclaration de fonction, void display usage(void), en ligne 5. Ce programme possde de nombreuses instructions (lignes 13, 15, 16, 19, 21, 22, 25, 27, 28, 30, 31, 36, et 37). Les lignes 34 38 reprsentent la dnition de fonction display usage. La ligne 1 est une ligne de commentaires et des accolades sparent les diffrents blocs du programme. list_it.c appelle plusieurs fonctions. Les fonctions de bibliothque utilises sont exit() en lignes 16, 22 et 31, fopen() en ligne 19, fprintf() en lignes 21, 28, 36, et 37, lire clavier() en ligne 27 (notre fonction dnie dans lexemple pratique 1), enn fclose() en ligne 30. display usage() est une fonction utilisateur. Toutes ces fonctions sont traites plus loin dans ce livre.

Rsum
Ce chapitre court a abord un sujet important : les principaux composants dun programme C. Vous avez appris que la fonction main() est obligatoire et que les instructions du programme permettent de transmettre vos ordres lordinateur. Ce chapitre a aussi introduit les variables, leurs dnitions, et vous a expliqu comment et pourquoi introduire des commentaires dans le code source. Un programme C peut utiliser deux types de fonctions : les fonctions de bibliothque qui sont fournies avec le compilateur, et les fonctions utilisateur qui sont cres par le programmeur.

Q&R
Q Les commentaires ont-ils une inuence sur le droulement du programme ? R Les commentaires sont destins aux programmeurs. Lorsque le compilateur converti le code source en code objet, il supprime tous les blancs et commentaires. Ils nont donc aucune inuence sur lexcution du programme. Les blancs et commentaires permettent simplement de clarier le code source pour faciliter la lecture et la maintenance du programme. Q Quelle est la diffrence entre une instruction et un bloc ? R Un bloc est constitu dun groupe dinstructions entre accolades ({}).

http://fribok.blogspot.com/

Q Comment puis-je connatre les fonctions de bibliothque disponibles ? R Beaucoup de compilateurs sont livrs avec un manuel contenant toutes les fonctions de bibliothque. Elles sont gnralement classes par ordre alphabtique. LAnnexe E numre une grande partie des fonctions disponibles. Consultez-la avant de programmer, cela vous pargnera de crer des fonctions qui existent dj dans la bibliothque.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre. Essayez de comprendre les rponses fournies dans lAnnexe G avant de passer au chapitre suivant.

Quiz
1. Comment appelle-t-on un groupe dune ou plusieurs instructions entre accolades ? 2. Quel est llment obligatoire dun programme C ? 3. Comment peut-t-on introduire des commentaires dans un programme ? Pour quelle raison doit-on documenter les programmes ? 4. Quest-ce quune fonction ? 5. Quels sont les deux types de fonctions disponibles en langage C et quelles sont leurs diffrences ? 6. quoi sert lappel #include? 7. Peut-on imbriquer des commentaires ? 8. Peut-on faire des commentaires sur plus dune ligne ? 9. Quel est lautre nom dun chier inclus ? 10. Quest-ce quun chier inclus ?

Exercice
1. crivez le programme le plus court possible. 2. tudiez le programme suivant :
1: /* ex2-2.c */ 2: #include <stdio.h> 3: 4: void display_line(void); 5: 6: int main() 7: { 8:display_line(); 9:printf("\n Le langageC en 21 jours!\n");

http://fribok.blogspot.com/

10:display_line(); 11: 12:exit(EXIT_SUCCESS); 13: } 14: 15: /* Affichage dune lignedasterisques */ 16: void display_line(void) 17: { 18:int counter; 19: 20:for(counter = 0; counter < 21; counter++) 21:printf("*"); 22: }

a) Quelles sont les lignes qui contiennent des instructions ? b) Dans quelles lignes se situent les dnitions de variables ? c) Quels sont les numros de ligne des dclarations de fonction ? d) Quelles lignes contiennent les dnitions de fonction ? e) Quelles sont les lignes qui ont des commentaires ? 3. crivez une ligne de commentaires. 4. Que fait le programme suivant ? (saisissez-le, compilez et excutez-le)
1: /* ex2-4.c */ 2: #include <stdio.h> 3: #include <string.h> 4: int main() 5: { 6:int ctr; 7: 8:for(ctr = 65; ctr < 91; ctr++) 9:printf("%c", ctr); 10: 11:exit(EXIT_SUCCESS); 12: } 13: /* fin du programme */

5. Que fait le programme suivant ? (saisissez-le, compilez, et excutez-le)


1: /* ex2-5.c */ 2: #include <stdio.h> 3: 4: int main() 5: { 6:char buffer[256]; 7: 8:printf("Entrez votre nom et appuyez sur Entre:\n"); 9:lire_clavier(buffer, sizeof(buffer)); 10: 11:printf("\nVotre nom contient%d caractres.", strlen(buffer)); 12: 13:exit(EXIT_SUCCESS); 14: }

http://fribok.blogspot.com/

3
Constantes et variables numriques
Les programmes dordinateur travaillent avec diffrents types de donnes et ont besoin de mmoire pour les stocker. Le langage C peut stocker des donnes sous formes de variable ou de constante avec de multiples options. Une variable dispose dune zone de stockage en mmoire et sa valeur peut changer en cours de programme. Une constante, au contraire, contient une valeur xe. Aujourdhui, vous allez apprendre :

Comment crer un nom de variable Comment utiliser les diffrents types de variable numrique Les diffrences entre caractres et valeurs numriques Comment dclarer et initialiser les variables numriques Quels sont les deux types de constantes numriques du langage C

Avant daborder les variables, vous devez connatre les principes de fonctionnement de la mmoire de votre ordinateur.

http://fribok.blogspot.com/

La mmoire
Si vous savez dj comment fonctionne la mmoire de votre ordinateur, vous pouvez passer au paragraphe suivant. Les informations qui suivent vont permettre de mieux comprendre certains aspects de la programmation C. Un ordinateur utilise de la mmoire vive (RAM, Random Access Memory) pour stocker des informations pendant son fonctionnement. Cette mmoire se situe dans une puce lintrieur de votre ordinateur. La mmoire vive est volatile, ce qui signie quelle est alloue ou libre pour de nouvelles informations aussi souvent que ncessaire. Cela signie aussi quelle ne fonctionne que lorsque lordinateur est sous tension. Lorsque vous le dbranchez, vous perdez toutes les informations qui sy trouvaient. La quantit de mmoire vive installe sur chaque ordinateur est variable. On lexprime en multiples doctets (mgaoctets ou gigaoctets). Si autrefois la mmoire tait compte, nos ordinateurs disposent aujourdhui de mgaoctets, voire de gigaoctets, et les programmeurs ont la fcheuse tendance lutiliser sans compter. Loctet est lunit de base de la mmoire ordinateur. Le Chapitre 20 traite de cette notion doctet. Le Tableau 3.1 vous donne quelques exemples du nombre doctets ncessaires pour stocker diffrentes sortes de donnes.
Tableau 3.1 : Exemples de tailles mmoire

Donne
Le caractre x Le nombre 500 Le nombre 241,105 La phrase "japprends le C" Une page de manuel

Nombre doctets ncessaires


1 2 4 25 Environ 3 000

La mmoire RAM est sollicite de faon squentielle et chaque octet est identi par une adresse unique. Cette adresse commence zro, pour le premier octet de mmoire, et sincrmente chaque octet en squence jusqu la limite du systme. Ces adresses sont gres automatiquement par votre compilateur. La mmoire vive a plusieurs fonctions, mais celle qui vous intresse en tant que programmeur est le stockage des donnes. Quelle que soit la tche ralise par votre programme, il

http://fribok.blogspot.com/

travaille avec des donnes qui sont stockes dans la mmoire vive de votre ordinateur pendant toute la dure de lexcution. Maintenant que vous connaissez ses principes de fonctionnement, nous pouvons tudier comment le langage C utilise cette mmoire pour stocker ses informations.

Les variables
Une variable est le nom dune zone mmoire de votre ordinateur. En utilisant ce nom dans votre programme, vous adressez la donne qui y est stocke.

Les noms de variable


Avant dutiliser une variable dans votre programme, vous devez crer un nom de variable qui doit respecter plusieurs rgles :

Ce nom peut contenir des lettres, des chiffres et le caractre ( ). Le premier caractre doit tre une lettre. Le caractre ( ) est aussi autoris, mais il nest pas recommand. Les lettres majuscules sont diffrentes des minuscules. Par exemple, compte et Compte ne reprsentent pas la mme variable. Il ne faut pas utiliser les mots cls, ils font partie du langage C. LAnnexe B fournit une liste complte des 33 mots cls du C.

Voici quelques exemples de noms de variables C :


Nom de la variable Pourcent y2x5 fg7h profit annuel taxe 1990 compte#courant double 9puits Validit
Correct Correct Correct Correct, mais dconseill Incorrect : contient le caractre interdit # Incorrect : double est un mot cl Incorrect : le 1er caractre est un chiffre

Certains compilateurs ne considrent que les 31 premiers caractres dun nom de variable, mme si celui-ci peut tre plus long. Cela permet de donner des noms qui retent le

http://fribok.blogspot.com/

type de donne qui y est sauvegard. Par exemple, un programme qui calcule des chances de prt pourrait stocker la valeur du taux dintrt dans une variable appele taux interets. Son utilisation en devient plus aise et le programme sera plus facile lire et comprendre. Il existe de nombreuses conventions pour ces noms de variables. Nous venons den voir un exemple en utilisant le caractre ( ) pour sparer des mots lintrieur du nom de la variable. Comme nous lavons vu, cette sparation permet de linterprter plus facilement. Une seconde solution consiste remplacer lespace par une lettre majuscule. Notre exemple prcdent taux interets, deviendrait TauxInterets. Cette notation est de plus en plus rpandue parce quil est plus facile de taper une lettre majuscule que le caractre ( ). Nous lavons utilis dans ce livre parce que la lecture en est plus facile.
eils Cons

faire Utiliser des noms de variables mnmotechniques. Se xer une convention pour les noms de variables. ne pas faire Ne pas faire prcder les noms de variables du caractre ( ), ou les crire en lettres majuscules alors que ce nest pas ncessaire.

Les types de variables numriques


Il existe en C plusieurs types de variable numrique. Leurs diffrences sexpliquent par le fait que des valeurs numriques selon leur taille ont des besoins de mmoire diffrents et que les oprations mathmatiques ne seffectuent pas de la mme faon selon le type de variables. Les petits entiers (par exemple 1, 199 et 8) demandent peu despace mmoire pour tre stocks et les oprations mathmatiques (additions, multiplications, etc.) sont ralises trs rapidement par votre ordinateur. Les grands nombres et les valeurs en virgule ottante (123 000 000 ou 0,000000871256, par exemple), au contraire, ncessitent plus despace mmoire et les oprations mathmatiques sont plus longues. En utilisant le type de variables appropri, vous optimisez lexcution de votre programme. Voici les deux principales catgories de variables numriques C :

Les variables entires qui sont un nombre entier positif ou ngatif, ou le zro. Les variables virgule ottante qui contiennent des valeurs pouvant avoir des chiffres aprs la virgule (ce sont les nombres rels).

http://fribok.blogspot.com/

Chacune de ces catgories se divise en plusieurs types de variables. Le Tableau 3.2 rcapitule ces diffrents types et vous donne lespace mmoire ncessaire pour stocker chacune de ces variables si vous utilisez un micro-ordinateur architecture 16 bits.
Tableau 3.2 : Les types de donnes numriques en C (reprsentation ILP32)

Type de variable
Caractre Entier court Entier Entier long Caractre non sign Entier court non sign Entier non sign Entier long non sign Simple prcision virgule ottante Double prcision virgule ottante

Mot cl char short int long unsigned char unsigned short unsigned int unsigned long float double

Octets ncessaires
1 2 4 4 1 2 4 4 4 8

Intervalle des valeurs


128 127 32 768 32 767 2 147 483 648 2 147 438 647 2 147 483 648 2 147 438 647 0 255 0 65 535 0 4 294 967 295 0 4 294 967 295 1,2 E38 3,4 E38 * 2,2 E308 1,8 E308 **

* Valeur approximative : prcision = 7 chiffres. ** Valeur approximative : prcision = 19 chiffres

Valeur approximative signie la plus haute et la plus petite valeur quune variable donne puisse recevoir. Prcision indique la prcision avec laquelle la variable est stocke (par exemple, pour valuer 1/3, la rponse est 0,333 avec des 3 linni ; une variable avec une prcision de 7 scrira avec sept chiffres 3 aprs la virgule). Vous pouvez remarquer que dans le Tableau 3.2 les types de variables int et long sont identiques. Cela est vrai sur des systmes compatibles PC en 32 bits, en reprsentation ILP32 mais ces deux variables peuvent tre diffrentes sur dautres types de matriels. Sur un ancien systme 16 bits, long et int nont pas la mme taille. La taille de short est de 2 octets, alors que celle de int est de 4. La portabilit du langage C exige donc deux mots cls diffrents pour ces deux types. Les variables entires sont des nombres rels par dfaut, elles nont pas de mot cl particulier. Vous pouvez toutefois inclure le mot cl signed si vous le dsirez. Les mots cls du

http://fribok.blogspot.com/

Tableau 3.2 sont utiliss dans les dclarations de variable, qui sont traites dans le prochain paragraphe. Le Listing 3.1 va permettre de connatre la taille des variables sur votre ordinateur. Ne soyez pas surpris si vos rsultats sont diffrents de ceux prsents ci-aprs. Listing 3.1 : Ce programme afche la taille des types de variables
1: /* sizeof.cCe programme vous donne la taille des types */ 2: /*variablesC en octets */ 3: 4: #include <stdio.h> 5: 6: int main() 7: { 8: 9:printf("\n char a une taille de%d octets", sizeof(char)); 10:printf("\n int a une taille de%d octets", sizeof(int)); 11:printf("\n short a une taille de%d octets", sizeof(short)); 12:printf("\n long a une taille de%d octets", sizeof(long)); 13:printf("\n unsigned char a une taille de%d octets", 14:sizeof(unsigned char)); 15:printf("\n unsigned int a une taille de%d octets", 16:sizeof(unsigned int)); 17:printf("\n unsigned short a une taille de%d octets", 18:sizeof(unsigned short)); 19:printf("\n unsigned long a une taille de%d octets", 20:sizeof(unsigned long)); 21:printf("\n float a une taille de%d octets",sizeof(float)); 22:printf("\n double a une taille de%d octets\n",sizeof(double)); 23: 24:exit(EXIT_SUCCESS); 25: } chara inta shorta longa unsigned chara unsigned inta unsigned shorta unsigned longa floata doublea une une une une une une une une une une taille taille taille taille taille taille taille taille taille taille de de de de de de de de de de 1 4 2 4 1 4 2 4 4 8 octets octets octets octets octets octets octets octets octets octets

http://fribok.blogspot.com/

Analyse Vous connaissez maintenant la taille de chaque type de variable sur votre ordinateur. Si vous utilisez un PC en mode 32 bits, vos chiffres devraient correspondre ceux du Tableau 3.2. Certaines parties de ce programme doivent vous sembler familires. Les lignes 1 et 2 sont des commentaires avec le nom du programme et une brve description. La ligne 4 appelle le chier en-tte standard pour lafchage des informations lcran. Ce programme ne contient que la fonction principale main() en lignes 7 25. Les lignes 9 22 afchent la taille de chaque type de variable laide de loprateur sizeof (voir Chapitre 19). La ligne 24 du programme renvoie la valeur EXIT_SUCCESS au systme dexploitation avant la n de lexcution du programme. Voici les caractristiques imposes par la norme ANSI :

La taille dun caractre est dun octet. La taille dune variable short est infrieure ou gale celle dune variable int. La taille dune variable int est infrieure ou gale celle dune variable long. La taille dune variable non signe est gale la taille d une variable int. La taille dune variable float est infrieure ou gale la taille d une variable double.

Les dclarations de variables


Avant dutiliser une variable dans un programme C, il faut la dclarer. Cette dclaration indiquera au compilateur le nom et le type de la variable et elle pourra linitialiser une certaine valeur. Si votre programme utilise une variable qui na pas t dclare, le compilateur gnre un message derreur. Une dclaration de variable a la forme suivante :
typename varname;

typename indique le type de variable et doit faire partie des mots cls rpertoris dans le Tableau 3.2. varname est le nom de la variable, et doit suivre les rgles mentionnes plus haut. Vous pouvez dclarer plusieurs variables du mme type sur une seule ligne en les sparant par des virgules.
int count, number, start;/* trois variables entires */ float percent, total;/* deux variables virgule flottante */

Le Chapitre 12 vous apprendra que lemplacement des dclarations de variable dans le code source est important, parce quil affecte la faon dont le programme va utiliser ces variables. ce stade de votre tude, vous pouvez placer toutes les dclarations de variable juste avant le dbut de la fonction main().

http://fribok.blogspot.com/

Le mot cl typedef
Le mot cl typedef permet de crer un synonyme pour un type de donne existant. Par exemple, linstruction :
typedef int entier;

cre le synonyme entier pour int. Vous pourrez ainsi utiliser entier pour dnir des variables de type int, comme dans lexemple suivant :
entier compte;

typedef ne crent pas un nouveau type de donne, il permet seulement dutiliser un nom diffrent pour un type de donne dj dnie. Lusage le plus frquent de typedef concerne les donnes agrges qui sont expliques au Chapitre 11.

Initialisation des variables numriques


La dclaration de variable permet au compilateur de rserver lespace mmoire destin cette variable. La donne qui sera stocke dans cet emplacement, la valeur de la variable, nest pas encore dnie. Avant dtre utilise, la variable dclare doit tre initialise. Cela peut se faire en utilisant une instruction dinitialisation comme dans notre exemple :
int count;/* Rservation de la mmoire pour count */ count = 0;/* Stocke 0 dans count */

Le signe gal fait partie des oprateurs du langage C. En programmation, ce signe na pas le mme sens quen algbre. Si vous crivez :
x = 12

dans une instruction algbrique, vous noncez un fait : "x = 12". En langage C, la signication est diffrente : "donner la valeur 12 la variable appele x". Vous pouvez initialiser une variable au moment de sa dclaration. Il suft de faire suivre le nom de variable, dans linstruction de dclaration, du signe gal suivi de la valeur initiale :
int count = 0; double percent = 0.01, taxrate = 28.5;

Attention, il ne faut pas initialiser la variable avec une valeur qui ne correspond pas au type dclar. Voici deux exemples dinitialisations incorrectes :
int poids = 100000; unsigned int valeur = 2500;

http://fribok.blogspot.com/

Le compilateur ne dtecte pas ce genre derreur, et le programme pourrait vous donner des rsultats surprenants.
eils Cons

faire Connatre la taille en octets des diffrents types de variables sur votre ordinateur. Utiliser typedef pour faciliter la lecture de vos programmes. Initialiser les variables dans linstruction de dclaration chaque fois que cest possible. ne pas faire Ne pas utiliser une variable oat ou double si vous ne stockez que des valeurs entires. Ne pas essayer de stocker des nombres dans des variables de type trop petit pour les recevoir. Ne pas stocker des nombres ngatifs dans des variables de type unsigned.

Les constantes
Une constante est un emplacement mmoire utilis par votre programme. linverse dune variable, la valeur stocke dans une constante ne peut changer pendant lexcution du programme. Le langage C possde deux types de constantes qui ont chacune un usage spcique.

Les constantes littrales


Une constante littrale est une valeur qui est introduite directement dans le code source. Voici deux exemples :
int count = 20; float tax_rate = 0.28;

20 et 0.28 sont des constantes littrales. Ces deux instructions stockent ces valeurs dans les variables count et tax rate. La valeur qui contient un point dcimal est une constante virgule ottante, lautre est une constante entire. Une constante avec virgule ottante est considre par le compilateur C comme un nombre double prcision. Les constantes avec virgule ottante peuvent tre reprsentes avec une notation dcimale standard :
123.456 0.019 100.

http://fribok.blogspot.com/

La troisime constante, 100., sera traite par le compilateur C en valeur double prcision cause de son point dcimal. Sans point dcimal, elle aurait t traite comme une constante entire. Les constantes virgule ottante peuvent tre reprsentes en notation scientique. La notation scientique reprsente un nombre par sa partie dcimal multiplie par dix une puissance positive ou ngative. Cette notation est particulirement utile pour exprimer des valeurs trs grandes ou trs petites. En langage C, le nombre dcimal est immdiatement suivi de E ou e puis de lexposant :
1.23E21.23 fois 10 la puissance 2, ou 123 4.08e64.08 fois 10 la puissance 6, ou 4080000 0.85e40.85 fois 10 la puissance 4, ou 0.000085

Une constante sans point dcimal est considre comme un nombre entier par le compilateur. Il existe trois notations diffrentes pour les constantes entires :

Une constante qui commence par un chiffre diffrent de 0 est interprte comme un entier dcimal (systme numrique standard en base 10). Les constantes dcimales sexpriment laide des chiffres 0 9 accompagns dun signe moins ou plus. Une constante qui commence par le chiffre 0 sexprime en octal (systme numrique en base 8). Une constante en octal peut contenir les chiffres 0 7 accompagns du signe moins ou plus. Une constante qui commence par 0x ou 0X est interprte comme une constante hexadcimale (systme numrique en base 16). Les constantes hexadcimales sexpriment laide des chiffres 0 9, des lettres A F, et du signe moins ou plus. Les notations hexadcimales et dcimales sont traites dans lAnnexe C.

Info

Les constantes symboliques


Une constante symbolique est une constante reprsente par un nom (symbole) dans votre programme. Comme la constante littrale, cette constante symbolique ne peut changer. Vous utilisez son nom dans le programme chaque fois que vous avez besoin de sa valeur. Cette valeur doit tre initialise une fois au moment de la dnition de la variable. Ces constantes ont deux avantages sur les constantes littrales. Supposons que vous criviez un programme qui ralise des calculs gomtriques. Ce programme aura souvent

http://fribok.blogspot.com/

besoin de la valeur (3,14159). Par exemple, pour calculer la circonfrence et laire dun cercle dont on connat le rayon, vous pourriez crire :
circonference = 3.14159* (2 * rayon); aire = 3.14159* (rayon) * (rayon);

Lastrisque (*) est loprateur de multiplication du langage C (voir Chapitre 4). La premire instruction signie "multiplier par 2 la valeur stocke dans la variable rayon, puis multiplier le rsultat par 3,14159, enn, stocker le rsultat dans la variable circonf rence". Si vous dnissez une constante symbolique de nom PI et de valeur 3,14, vous pourriez crire :
circonference = PI * (2 * rayon); aire = PI * (rayon) * (rayon);

Ces instructions sont plus faciles lire et comprendre. Le second avantage des constantes symboliques apparat quand vous avez besoin de changer cette constante. Si vous dcidez, dans lexemple prcdent, dutiliser une valeur de p plus prcise (3,14159 plutt que 3,14), vous ne devez changer cette valeur quune fois, au niveau de la dnition. Avec une constante littrale, vous devez changer chaque occurrence du code source. Il y a deux mthodes en langage C pour dnir une constante symbolique : lordre #define et le mot cl const. #define est une commande du prprocesseur qui sera traite au Chapitre 21. Linstruction suivante cre une constante appele CONSTNAME avec la valeur literal:
#define CONSTNAME literal

Literal reprsente une constante littrale. Par convention, le nom des constantes symboliques scrit en lettres majuscules. Cela permet de les distinguer des noms de variables qui sont par convention en lettres minuscules. Dans lexemple prcdent, la commande #define aurait t :
#define PI 3.14159

Remarquez que cette instruction ne se termine pas par un point-virgule (;). La commande #define peut se trouver nimporte o dans le code source, mais son effet est limit la partie de code qui la suit. En gnral, les programmeurs groupent tous les #define ensemble, au dbut du chier, avant la fonction main().

http://fribok.blogspot.com/

Fonctionnement de #define
Le rle de #defineest dindiquer au compilateur la directive : "dans le code source, remplacer CONSTNAME par literal". Vous auriez obtenu le mme rsultat en faisant tous les changements manuellement avec un diteur. Bien sur, #define ne remplace pas les occurrences qui pourraient se trouver lintrieur dun mot plus long, entre guillemets, ou dans un commentaire du programme. Dans le code suivant, les valeurs de des deuxime et troisime lignes resteraient identiques :
#define PI 3.14159 /* vous avez dfini la constante PI. */ #define PIPETTE 100

Dnition des constantes avec le mot cl const


La seconde mthode pour dnir une constante symbolique est d utiliser le mot cl const qui peut modier nimporte quelle dclaration de variable. Une variable dnie avec ce mot cl ne peut tre modie pendant lexcution du programme. Voici quelques exemples :
const int count = 100; const float pi = 3.14159; const long debt = 12000000, float tax_rate = 0.21;

const sapplique sur toutes les variables de la ligne de dclaration. debt et tax rate sont des constantes symboliques. Si votre programme essaie de modier une variable const, le compilateur gnre un message derreur comme dans lexemple suivant :
const int count = 100; count = 200; /* Pas de compilation! On ne peut pas changer */ /* la valeurdune constante. */

Les diffrences entre une constante symbolique cre avec linstruction #define et une autre, cre avec le mot cl const, concernent les pointeurs et la porte des variables. Ce sont deux aspects importants de la programmation C qui sont traits aux Chapitres 9 et 12. tudions le code du Listing 3.2 qui illustre ces dclarations de variables et qui utilise des constantes symboliques et littrales. Ce programme demande lutilisateur dentrer son poids et son anne de naissance. Il afche ensuite le poids de lutilisateur en grammes et lge quil avait en lan 2000. Vous pouvez saisir, compiler, et excuter ce programme en suivant la procdure du Chapitre 1. Listing 3.2 : Utilisation des variables et des constantes
1:/* Exemple dutilisation de variables et de constantes */ 2:#include <stdio.h> 3: #include <stdlib.h>

http://fribok.blogspot.com/

4:/* Dfinition dune constante pour convertir les livres en grammes */ 5:#define GRAMS_PAR_LIVRE 454 6: 7:/* Dfinition dune constante pour le dbut du sicle */ 8:const int DEBUT_SIECLE = 2000; 9: 10:/* Dclaration des variables requises */ 11:int poids_en_grams, poids_en_livres; 12:int an_naissance, age_en_2000; 13: 14:int main() 15:{ 16:/* Lecture des donnes de lutilisateur */ 17: 18:printf("Entrez votre poids en livres: "); 19:scanf("%d", &poids_en_livres); 20:printf("Entrez votre anne de naissance: "); 21:scanf("%d", &an_naissance); 22: 23:/* conversions */ 24: 25:poids_en_grams = poids_en_livres * GRAMS_PAR_LIVRE; 26:age_en_2000 = DEBUT_SIECLE an_naissance; 27: 28:/* Affichage des rsultats */ 29: 30:printf("\nVotre poids en grammes =%d", poids_en_grams); 31:printf("\nEn lan %d vous avez eu%d ans.\n", 32: DEBUT_SIECLE,age_en_2000); 33: 34:exit(EXIT_SUCCESS); 35:} Entrez votre poids en livres: 175 Entrez votre anne de naissance: 1990 Votre poids en grammes = 79450 En lan 2000 vous avez eu 10 ans.

Analyse La dclaration des deux types de constantes symboliques se fait en lignes 5 et 8. La constante de la ligne 5 permet de comprendre facilement la ligne 25. Les lignes 11 et 12 dclarent les variables utilises dans le programme. Les lignes 18 et 20 demandent lutilisateur dentrer ses donnes, et les lignes 19 et 21 rcuprent les informations de lutilisateur partir de lcran. Les fonctions de bibliothque printf() et scanf() seront tudies dans les prochains chapitres. Le calcul du poids et de lge seffectue aux lignes 25 et 26, et le rsultat est afch avec les lignes 30 et 31.

http://fribok.blogspot.com/

eils Cons

faire Utiliser des constantes pour faciliter la lecture de votre programme. ne pas faire Essayer de stocker une valeur dans une constante qui a dj t initialise.

Rsum
Vous venez dtudier les variables numriques qui sont utilises par les programmes C pour stocker des donnes pendant lexcution. Il existe deux classes de variables numriques, entire et virgule ottante, qui ont chacune leurs propres types de variables. Le type que vous choisirez (int, long, float, ou double) dpend de la nature de la donne stocker dans cette variable. La dclaration doit prcder lutilisation de cette variable et elle transmet au compilateur le nom et le type de la variable. linverse des variables, les deux types de constantes, littrale et symbolique, ont une valeur qui ne peut changer pendant lexcution du programme. La constante littrale est introduite dans le code source au moment de son utilisation. La constante symbolique est cre avec linstruction #define ou avec le mot cl const. Elle est rfrence par son nom.

Q&R
Q Pourquoi ne pas toujours utiliser les variables long int qui peuvent contenir de grands nombres plutt que des variables int? R Une variable long int peut tre plus gourmande en mmoire. Cela ne fait pas de diffrence dans un petit programme, mais plus il sera gros, plus il deviendra important de bien grer la mmoire utilise. Q Que se passera-t-il si jessaye de stocker un nombre dcimal dans un entier ? R Vous pouvez stocker un nombre avec une dcimale dans une variable int. Si cette variable est une variable constante, votre compilateur va certainement vous envoyer un warning. La valeur stocke aura perdu sa partie dcimale. Par exemple, si vous donnez la valeur 3,14 la variable entire pi, pi ne contiendra que la valeur 3. Q Que se passera-t-il si jessaye de stocker un nombre dans un type trop petit pour le recevoir ? R Beaucoup de compilateurs ne signalent pas ce type derreur. Le nombre sera tronqu. Par exemple, si vous voulez stocker 32768 dans un entier sign 2 octets, lentier

http://fribok.blogspot.com/

contiendra la valeur 32768. Si vous assignez la valeur 65535 cet entier, il contiendra la valeur 1. Si vous soustrayez la valeur maximum sauvegarde dans le Champ vous obtenez la valeur qui sera stocke. Q Que se passera-t-il si je mets un nombre ngatif dans une variable non signe ? R Comme pour la question prcdente, il est possible que votre compilateur ne signale pas ce type derreur. Il fera la mme transformation quavec un nombre trop long. Par exemple, si vous stockez 1 dans une variable short unsigned de 2 octets, le compilateur stockera dans la variable le nombre le plus grand possible (65535). Q Quelles diffrences y a-t-il entre une constante symbolique cre avec lordre #define et une autre cre avec le mot cl const? R Les diffrences se situent au niveau des pointeurs et de la porte de la variable. Ces deux aspects importants de la programmation C sont traits aux Chapitres 9 et 12. Retenez aujourdhui que lutilisation de #dene pour crer des constantes simplie la lecture de votre programme.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre. Essayez de comprendre les rponses fournies dans lAnnexe G avant de passer au chapitre suivant.

Quiz
1. Quelle est la diffrence entre une variable entire et une variable virgule ottante ? 2. Donnez deux raisons dutiliser une variable virgule ottante double prcision plutt que la mme variable simple prcision. 3. Quelles sont les cinq rgles de la norme ANSI concernant lallocation de la taille des variables ? 4. Quelles sont les deux avantages utiliser une constante symbolique plutt quune constante littrale ? 5. Trouvez deux mthodes pour dnir une constante symbolique appele MAXIMUM qui aurait une valeur de 100. 6. Quels sont les caractres autoriss dans le nom dune variable C ?

http://fribok.blogspot.com/

7. Quelles sont les rgles suivre pour crer des noms de variables et de constantes ? 8. Quelle diffrence y a-t-il entre une constante symbolique et une constante littrale ? 9. Quelle est la valeur minimum que peut prendre une variable de type short?

Exercices
1. Quel type de variable convient le mieux pour stocker les valeurs suivantes : a) Lge dune personne. b) Le poids dune personne. c) Le rayon dun cercle. d) Votre salaire annuel. e) Le prix dun article. f) La note la plus haute dun test (supposons que ce soit toujours 100). g) La temprature. h) Le gain dune personne. i) La distance dune toile en kilomtres. 2. Donnez un nom appropri chaque variable de lexercice 1. 3. crivez les dclarations pour les variables de lexercice 2. 4. Dans la liste suivante, quels sont les noms de variable corrects ? a) 123variable. b) x. c) score_total. d) Poids_en_#s. e) one.0. f) gross-cost. g) RAYON. h) Rayon. i) rayon. j) cela_est_une_variable_pour_stocker_la_largeur

http://fribok.blogspot.com/

4
Instructions, expressions et oprateurs
Les programmes C sont constitus dinstructions qui contiennent, pour la plupart, des expressions et des oprateurs. Aujourdhui vous allez tudier :

Les instructions Les expressions Les oprateurs logiques, de comparaison et mathmatiques du langage C Les ordres de priorit ou la hirarchie des oprateurs Linstruction if

http://fribok.blogspot.com/

Les instructions
Une instruction reprsente une tche accomplir par lordinateur. En langage C, on crit une instruction par ligne et elle se termine par un point-virgule ( lexception de #define et #include qui sont traites au Chapitre 21). Par exemple :
x = 2+3;

est une instruction daffectation. Elle demande lordinateur dajouter 2 et 3 et dattribuer le rsultat la variable x.

Instructions et blancs
Le terme de blancs fait rfrence tout espace, tabulation ou ligne de blancs du code source. Quand le compilateur lit une instruction, il traite les caractres et le point-virgule de n. Il ignore absolument tous les blancs. Par exemple, linstruction :
x=2+3;

est quivalente :
x = 2+3;

ou mme :
x= 2 + 3;

Cela vous laisse une grande libert pour la mise en page de votre code. Cette rgle comporte cependant une exception, les constantes chane de caractres. Une chane est constitue de toute squence de caractres (y compris les blancs et tabulations) cerne par des guillemets. Le compilateur interprtera la squence entire. Vous pouvez crire par exemple :
printf( "Hello, world!" );

La forme nest pas suivre, mais la syntaxe est correcte. Linstruction suivante, au contraire, est incorrecte :
printf("Hello, world!");

http://fribok.blogspot.com/

En utilisant lantislash (\) comme dans lexemple suivant, vous effectuez un retour la ligne visible aussi bien dans le code qu lexcution :
printf("Hello,\ world!");

Un blanc pouvant aisment se cacher aprs un antislash, prfrez lutilisation de la squence \n pour vos retours la ligne.

Les instructions nulles


Si vous placez un point-virgule seul sur une ligne, vous avez cr une instruction nulle. Cette instruction neffectue aucune opration, mais vous apprendrez, dans les prochains chapitres, quelle peut se rvler utile.

Les blocs
Un bloc (ou instructions composes) est un groupe dinstructions entre accolades :
{ printf("Hello,"); printf("world!"); }

Les accolades peuvent se positionner de diffrentes faons. Lexemple suivant est quivalent au prcdent :
{printf(Hello,); printf(world!);}

En plaant les accolades sur une ligne spare, vous identierez plus facilement le dbut et la n du bloc, et vous viterez den oublier une.

eils Cons

faire Utiliser les blancs de manire cohrente. Isoler les accolades, le code sera plus facile lire. ne pas faire Rpartir une instruction sur plusieurs lignes alors que ce nest pas ncessaire. Il est prfrable de respecter la rgle dune instruction par ligne.

http://fribok.blogspot.com/

Les expressions
En langage C, on appelle expression tout ce qui reprsente une valeur numrique.

Les expressions simples


Lexpression la plus simple est constitue dune seule variable, dune constante littrale ou dune constante symbolique. Voici quatre exemples dexpressions :
Expression PI 20 taux 1.25 Description
Constante symbolique (dnie dans le programme) Constante littrale Variable Constante littrale

La valeur dune constante littrale est sa propre valeur. La valeur dune constante symbolique est celle qui a t dnie au niveau de linstruction #define. La valeur courante dune variable est celle qui lui a t attribue par le programme.

Les expressions complexes


Les expressions complexes sont constitues dexpressions plus simples avec des oprateurs. Par exemple :
2+8

est une expression forme de deux sous-expressions 2 et 8 et de loprateur daddition (+). La valeur de cette expression est 10. Vous pouvez aussi crire des expressions beaucoup plus complexes :
1.25 /8+5 * taux+taux * taux / cout

Quand une expression contient plusieurs oprateurs, son valuation dpend de lordre dans lequel les oprations sont effectues. Ce concept de hirarchie est expliqu plus loin dans le chapitre. Linstruction x=a+ 10; calcule lexpression a+ 10 et attribue le rsultat x. Comme lillustre la Figure 4.1, linstruction entire est elle-mme une expression qui attribue la variable situe gauche du signe gal le rsultat du calcul de droite.

http://fribok.blogspot.com/

Figure 4.1 Une instruction daffectation est ellemme une expression.

Evalu une certaine valeur

variable=une_expression;

Evalu la mme valeur

Ainsi, vous pouvez crire des instructions comme lexemple qui suit :
y = x = a+b;

ou
x = 6+ (y = 4+5);

Linstruction prcdente attribue la valeur 9 y, puis la valeur 15 x.

Les oprateurs
Un oprateur est un symbole qui dcrit une opration ou une action effectuer sur une ou plusieurs oprandes. En langage C, les oprandes sont toujours des expressions. Les oprateurs sont diviss en quatre catgories :

loprateur daffectation ; les oprateurs mathmatiques ; les oprateurs de comparaison ; les oprateurs logiques.

Loprateur daffectation
Loprateur daffectation est le signe gale (=). Dans un programme C, linstruction :
x = y;

ne signie pas "x gale y". Elle indique lordinateur "daffecter la valeur de y x". Cette instruction doit tre compose dune expression droite du signe gale, et dun nom de variable gauche de ce signe :
variable = expression;

http://fribok.blogspot.com/

Les oprateurs mathmatiques


Les oprateurs mathmatiques de C ralisent des oprations mathmatiques comme laddition ou la soustraction. Il en existe deux unaires et cinq binaires.

Les oprateurs mathmatiques unaires


Les oprateurs unaires oprent sur une seule valeur ou oprande.
Tableau 4.1 : Les oprateurs mathmatiques unaires du langage C

Oprateur
Incrmentation Dcrmentation

Symbole ++

Opration
Augmente de 1 la valeur de loprande Dcrmente de 1 la valeur de loprande

Exemples ++x, x++ x, x

Ces deux oprateurs ne peuvent tre utiliss quavec des variables. Lopration ralise est dajouter ou de soustraire 1 de loprande. Les instructions :
++x; y;

sont quivalentes aux instructions suivantes :


x = x+1; y = y 1;

Loprateur unaire peut tre plac avant (mode prx) ou aprs (mode postx) loprande :

En mode prx, lincrmentation et la dcrmentation sont effectues avant lutilisation de loprande. En mode postx les oprateurs dincrmentation et de dcrmentation modient loprande aprs son utilisation.

Cette explication sera plus claire avec un exemple :


x = 10; y = x++;

la suite de ces deux instructions, x a la valeur 11 et y la valeur 10. La valeur de x a t attribue y, puis x a t incrment. Les instructions suivantes, au contraire, donnent x et y la mme valeur 11 : x est incrment, puis sa valeur est affecte y.
x = 10; y = ++x;

http://fribok.blogspot.com/

Souvenez-vous que le signe (=) est loprateur daffectation, et non une instruction dgalit. Considrez-le comme un oprateur de "photocopie". Linstruction y = x signie "copier x dans y". Les transformations que pourra ensuite subir x nauront aucun effet sur y. Le Listing 4.1 illustre les diffrences entre les modes prx et postx. Listing 4.1 : unaire.c
1: /* Dmonstration des modes prfix et postfix */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int a, b; 6: 7: int main() 8: { 9:/* initialise a et b la valeur 5 */ 10: 11:a = b = 5; 12: 13:/* on les affiche, en les dcrmentant chaque fois */ 14:/* mode prfixe pour b, mode postfix pour a */ 15: 16:printf("\n%d%d", a , b); 17:printf("\n%d%d", a , b); 18:printf("\n%d%d", a , b); 19:printf("\n%d%d", a , b); 20:printf("\n%d%d\n", a , b); 21: 22:exit(EXIT_SUCCESS); 23: } 54 43 32 21 10

Analyse Ce programme dclare les deux variables a et b en ligne 5 puis leur donne la valeur 5 en ligne 11. Chacune des instructions printf() des lignes 16 20 dcrmente ces variables de 1 : la dcrmentation de a seffectue aprs son afchage, celle de b seffectue avant.

http://fribok.blogspot.com/

Oprateurs mathmatiques binaires


Les oprateurs binaires du langage C travaillent avec deux oprandes.
Tableau 4.2 : Les oprateurs mathmatiques binaires du langage C

Oprateur
Addition Soustraction Multiplication Division Modulo

Symbole +

Opration
Additionne les deux oprandes Soustrait la valeur du second oprande la valeur du premier

Exemple x+y x y

* / %

Multiplie les deux oprandes Divise le premier oprande par le second Donne le reste de la division du premier oprande par le second

x * y x / y x% y

Les quatre premiers oprateurs rpertoris dans le tableau sont des oprateurs familiers. Modulo, que vous ne connaissez peut-tre pas, vous donne le reste de la division du premier oprande par le second. Par exemple, 11 modulo 4 donne la valeur 3. Le Listing 4.2 vous montre comment utiliser loprateur modulo pour convertir des secondes en heures, minutes et secondes. Listing 4.2 : Utilisation de loprateur modulo
1: /* Utilisation de loprateur modulo */ 2: /* ce programme converti le nombre de secondes que vous lui */ 3: /* donnerez en heures, minutes, secondes. */ 4: #include <stdio.h> 5: #include <stdlib.h> 6: 7: /* Dfinition des constantes */ 8: 9: #define SECS_PER_MIN 60 10: #define SECS_PER_HOUR 3600 11: 12: unsigned seconds, minutes, hours, secs_left, mins_left; 13: 14: int main() 15: { 16:/* Saisie du nombre de secondes */ 17: 18:printf("Entrez le nombre de secondes (< 65000): "); 19:scanf("%d", &seconds); 20: 21:hours = seconds / SECS_PER_HOUR; 22:minutes = seconds / SECS_PER_MIN; 23:mins_left = minutes% SECS_PER_MIN;

http://fribok.blogspot.com/

24:secs_left = seconds% SECS_PER_MIN; 25: 26:printf("%u secondes reprsentent ", seconds); 27:printf("%u h,%u m, et%u s\n", hours, mins_left, secs_left); 28: 29:exit(EXIT_SUCCESS); 30: } $ list4_2 Entrez le nombre de secondes (< 65000): 60 60 secondes correspondent 0 h, 1 m, et 0 s $ list4_2 Entrez le nombre de secondes (< 65000): 10000 10000 secondes correspondent 2 h, 46 m, et 40 s

Analyse Les commentaires des lignes 1 3 indiquent ce que fait le programme. La ligne 5 appelle lindispensable chier en-tte et les lignes 8 et 9 dnissent les deux constantes SECS PER MIN et SECS PER HOUR. Les dclarations de variables se font en ligne 12. Certains programmeurs prfrent dclarer une variable par ligne. Comme avec beaucoup dlments du langage C, vous pouvez choisir le style que vous voulez. La fonction principale main() se trouve en ligne 14. La ligne 18, avec la fonction printf(), demande lutilisateur de taper le nombre de secondes qui est rcupr par le programme avec la fonction scanf() de la ligne 19. Cette fonction stocke la valeur lue dans la variable seconds. Le Chapitre 7 vous donnera plus de dtails sur les deux fonctions printf() et scanf(). La ligne 21 est une expression qui calcule le nombre dheures en divisant le nombre de secondes par la constante SECS PER HOUR. hours tant une variable entire, la valeur restante est ignore. La ligne 22 utilise la mme logique pour dterminer le nombre total de minutes. Les lignes 23 et 24 utilisent loprateur modulo pour diviser respectivement les heures et les minutes et conserver les minutes et les secondes restantes. Les lignes 26 et 27 afchent les valeurs calcules. Ce programme se termine en renvoyant la valeur 0 en ligne 29.

Hirarchie des oprateurs et parenthses


Quand une expression possde plusieurs oprateurs, lordre dans lequel les oprations sont effectues est important :
x = 4+5 * 3;

Si la premire opration ralise est laddition, cela revient linstruction suivante et x prend la valeur 27 :
x = 9 * 3;

http://fribok.blogspot.com/

Au contraire, si la premire opration est la multiplication, vous obtenez linstruction qui suit et x prend la valeur 19 :
x = 4+15;

Des rgles de priorit, appeles hirarchie des oprateurs, sont ncessaires. Le Tableau 4.3 vous prsente la hirarchie des oprateurs mathmatiques du langage C en commenant par le plus "prioritaire".
Tableau 4.3 : Hirarchie des oprateurs mathmatiques du langage C

Oprateurs ++ * /% +

Priorit dexcution
1 2 3

Si une expression contient plusieurs oprateurs de mme niveau de priorit, les oprations sont ralises de gauche droite. Dans lexemple qui suit, loprateur modulo se trouvant gauche, (12 % 5) sera la premire opration effectue :
12% 5 * 2

La valeur de cette expression est 4 (12 % 5 donne 2; 2 fois 2 donne 4). Pour modier lordre de validation des oprations, le langage C permet dutiliser des parenthses. La sous-expression entre parenthses est la premire calcule quelle que soit la hirarchie des oprateurs. Dans le cas de notre premier exemple, si vous voulez ajouter 4 et 5 avant de les multiplier par trois, vous pourriez crire :
x = (4+5) * 3;

La valeur attribue x est 27. Une expression peut contenir des parenthses multiples ou imbriques. Dans le cas de parenthses imbriques, lvaluation se fait de "lintrieur" vers "lextrieur". Lexpression :
x = 25 (2 * (10+ (8 / 2)));

se calcule dans lordre suivant : 1. 2.


25 (2 * (10+4)) 25 (2 * 14)

http://fribok.blogspot.com/

3.

25 28

4. Lexpression nale x = 3 attribue la valeur 3 x. Vous pouvez placer des parenthses pour rendre une expression plus facile comprendre. Elles doivent toujours aller par paires, sinon le compilateur gnre un message derreur.

Ordre de traitement des sous-expressions


Une expression qui contient plusieurs oprateurs de mme niveau de priorit est value de gauche droite. Dans lexpression :
w * x / y * z

w est multipli par x, le rsultat de la multiplication est divis par y et le rsultat de la division est multipli par z. Si lexpression contient de multiples oprateurs de priorits diffrentes, lordre de traitement de gauche droite nest plus garanti. tudions lexemple suivant :
w * x / y+z / y

La multiplication et la division doivent tre traites avant laddition. Les rgles du langage ne permettent pas de savoir si w * x / y doit tre calcul avant ou aprs z / y. Si on transforme notre expression, le rsultat sera diffrent selon lordre dans lequel seront values les sous-expressions :
w * x / ++y+z / y

Si la sous-expression de gauche est la premire calcule, y est incrment quand la seconde expression est value. Si le calcul commence avec lexpression de droite, y nest pas incrment et le rsultat est diffrent. Vous devez viter dutiliser ce genre dexpression indtermine. La hirarchie de tous les oprateurs du langage C vous sera fournie la n de ce chapitre.
eils Cons

faire Utiliser des parenthses pour que lordre dvaluation des expressions ne soit pas ambigu. ne pas faire Surcharger une expression. Elle devient souvent plus claire si on la divise en plusieurs sous-expressions, tout particulirement avec des oprateurs unaires () ou (++).

http://fribok.blogspot.com/

Les oprateurs de comparaison


Les oprateurs de comparaison sont utiliss pour comparer des expressions en posant des questions du type "x est-il plus grand que 100 ?" ou "y est-il gal 0 ?". La valeur nale dune expression qui contient un oprateur de comparaison est "vrai" (diffrent de 0) ou "faux" (0). "Vrai" est quivalent 1 ou "oui". "Faux" est quivalent 0 ou "non".

Info

Tableau 4.4 : Les oprateurs de comparaisons du langage C

Oprateur
gal Suprieur Infrieur Suprieur ou gal Infrieur ou gal Diffrent

Symbole == > < >= <= !=

Question pose
Le premier oprande est-il gal au second ? Le premier oprande est-il plus grand que le second ? Le premier oprande est-il plus petit que le second ? Le premier oprande est-il suprieur ou gal au second ? Le premier oprande est-il infrieur ou gal au second ? Le premier oprande est-il diffrent du second ?

Exemple x==y x>y x<y x>=y x<=y x!=y

Tableau 4.5 : Exemples dutilisations des oprateurs de comparaison

Expression
5 == 1 5 > 1 5!= 1 (5+10) == (3 * 5)

Signication
La valeur 5 est-elle gale 1 ? 5 est-elle plus grande que 1 ? La valeur 5 est-elle diffrente de 1 ? Lexpression (5 + 10) est-elle gale (3 * 5) ?

Valeur faux vrai vrai vrai

eils Cons

faire Comprendre que le langage C interprte une expression vraie comme ayant une valeur non nulle et une expression fausse comme ayant la valeur 0.

http://fribok.blogspot.com/

ne pas faire
Confondre loprateur de comparaison (==) avec loprateur daffectation (=). Cest une des erreurs les plus courantes des programmeurs.

Utiliser le rsultat dun test (gnralement la valeur 1) dans une expression arithmtique.

Linstruction if
Les oprateurs de comparaison sont principalement utiliss dans les instructions if et while pour le contrle de lexcution du programme. Ce contrle permet de modier la rgle suivante : les instructions dun programme C sexcutent en squence, dans lordre dans lequel elles sont places dans le chier source. Une structure de contrle modie lordre dexcution des instructions. Une instruction de contrle peut provoquer lexcution de certaines instructions du programme plusieurs fois, ou pas dexcution du tout selon les circonstances. Linstruction if en fait partie, ainsi que do et while qui sont traites dans le Chapitre 6. Linstruction if value une expression, et oriente lexcution du programme en fonction du rsultat de cette valuation. La syntaxe est la suivante :
if (expression) instruction;

Si le rsultat de lvaluation est vrai, linstruction est excute. Dans le cas contraire, lexcution du programme se poursuit avec linstruction qui suit linstruction if. Notez que les deux lignes de notre exemple constituent linstruction if, ce ne sont pas des instructions spares. Une instruction if peut contrler lexcution de nombreuses lignes de code par lintermdiaire dun bloc. Comme nous lavons dni, un bloc est constitu dun groupe dinstructions cernes par des accolades et il est utilis de la mme faon quune instruction. Linstruction if peut donc prendre la forme suivante :
if (expression) { instruction 1; instruction 2; /* code supplmentaire si ncessaire */ instruction n; }

http://fribok.blogspot.com/

eils Cons

faire Dcaler les instructions lintrieur dun bloc pour. Cela concerne aussi les instructions if. ne pas faire Mettre un point-virgule la n de linstruction if. Cette instruction doit se terminer par une instruction de comparaison. Dans lexemple suivant, ins truction 1 est excute quel que soit le rsultat de la comparaison, car chaque ligne est value comme une instruction indpendante :
if (x == 2);/* il ne devrait pas y avoir de point-virgule! */ instruction 1;

Au cours de votre programmation, vous vous apercevrez que les instructions if sont surtout utilises avec des expressions de comparaison. En dautres termes, "Excute linstruction suivante seulement si telle condition est vraie". Voici un exemple :
if (x > y) y = x;

y prendra la valeur de x seulement si x est plus grand que y. Si x est plus petit, linstruction nest pas excute. Listing 4.3 : Linstruction if
1: /* Exemple dutilisation de linstruction de contrle if */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int x, y; 6: 7: int main() 8: { 9: /* Lecture des deux valeurs tester */ 10: 11:printf("\nEntrez une valeur entire pour x : "); 12:scanf("%d", &x); 13:printf("\nEntrez une valeur entire pour y : "); 14:scanf("%d", &y); 15: 16: /* Test des valeurs et affichage des rsultats */ 17: 18:if (x == y) 19:_printf("x est gal y\n"); 20: 21:if (x > y) 22:_printf("x est plus grand que y\n"); 23:

http://fribok.blogspot.com/

24:if (x < y) 25:_printf("x est plus petit que y\n"); 26: 27:exit(EXIT_SUCCESS); 28: } Entrez une valeur entire pour x: 100 Entrez une valeur entire pour y: 10 x est plus grand que y Entrez une valeur entire pour x: 10 Entrez une valeur entire pour y: 100 x est plus petit que y Entrez une valeur entire pour x: 10 Entrez une valeur entire pour y: 10 x est gal y

Analyse list4_3.c contient trois instructions if (lignes 18 25). La ligne 5 dclare les deux variables x et y, et les lignes 11 14 demandent lutilisateur dentrer des valeurs pour ces variables. Les lignes 18 25 utilisent linstruction if pour savoir si x est gal, suprieur ou infrieur y et afchent le rsultat. Les instructions lintrieur de linstruction if sont dcales pour faciliter la lecture du programme.

Info

La clause else
Une instruction if peut contenir une clause else comme le montre lexemple suivant :
if (expression) instruction1; else instruction2;

Si expression est value comme tant vraie, instruction1 est excute, sinon cest instruction2 qui est excute. Ces deux instructions peuvent tre remplaces par des blocs. Le Listing 4.4 vous prsente le Listing 4.3 rcrit avec des clauses else.

http://fribok.blogspot.com/

Listing 4.4 : Linstruction if avec une clause else


1: /* Exemple dutilisation de linstruction if avec la clause else 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int x, y; 6: 7: int main() 8: { 9:/* Lecture des deux valeurs tester */ 10: 11:printf("\nEntrez une valeur entire pour x: "); 12:scanf("%d", &x); 13:printf("\nEntrez une valeur entire pour y: "); 14:scanf("%d", &y); 15: 16:/* Test des valeurs et affichage des rsultats */ 17: 18:if (x == y) 19: printf("x est gal y\n"); 20:else 21: if (x > y) 22: printf("x est plus grand que y\n"); 23: else 24: printf("x est plus petit que y\n"); 25: 26:exit(EXIT_SUCCESS); 27: } Entrez une valeur entire pour x: 99 Entrez une valeur entire pour y: 8 x est plus grand que y Entrez une valeur entire pour x: 8 Entrez une valeur entire pour y: 99 x est plus petit que y Entrez une valeur entire pour x: 99 Entrez une valeur entire pour y: 99 x est gal y */

Analyse Les lignes 18 24 sont lgrement diffrentes du code source prcdent. La ligne 18 contrle toujours si x est gal y, mais si la comparaison est vraie, "x est gal y" est afch et le programme se termine sans excuter les lignes 20 24. La ligne 21 nest

http://fribok.blogspot.com/

excute que si lexpression "x gal y" est fausse. Si x est plus grand que y, la ligne 22 afche le message sinon la ligne 24 est excute. Ce listing a utilis une instruction if imbrique. Cela signie que cette instruction if fait partie dune autre instruction if. Dans notre exemple, Linstruction imbrique fait partie de la clause else de la premire instruction if.

Syntaxe de la commande if
Forme 1
if (expression) instruction1; instruction_suivante;

Linstruction if est ici dans sa forme la plus simple. Si expression est vraie, instruction1 est excute. Si expression est fausse, instruction1 est ignore. Forme 2
if (expression) instruction1; else instruction2; instruction suivante;

Cest la forme la plus courante. Si expression est vraie, instruction1 est excute, sinon cest instruction2 qui est excute. Forme 3
if (expression1) instruction1; else if (expression2) instruction2; else instruction3; instruction suivante;

Les instructions if sont imbriques. Si expression1 est vraie, instruction1 est excute. Dans le cas contraire, expression2 est value. Si cette dernire est vraie, instruction2 est excute. Si les deux expressions sont fausses, cest instruction3 qui est excute. Exemple 1
if (salaire > 45,0000) taxe = .30; else taxe = .25;

http://fribok.blogspot.com/

Exemple 2
if (age < 18) printf("mineur"); else if (age < 65) printf("adulte"); else printf("personne age");

valuation des expressions de comparaison


Une expression de comparaison est value la valeur (0) si elle est fausse, et une valeur non nulle (gnralement 1) si elle est vraie. Bien que ce type dexpression soit presque toujours inclus dans une structure de contrle (exemple if) sa valeur numrique peut tre utilise. Cela est proscrire car la valeur vraie peut prendre une valeur autre que 1 dans certaines circonstances. Listing 4.5 : valuation des expressions de comparaison
1: /* Exemple de lvaluation dexpressions de comparaison */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int a; 6: 7: int main() 8: { 9:a = (5 == 5);/* valu priori 1 */ 10:printf("a = (5 == 5)\na =%d\n", a); 11: 12:a = (5!= 5);/* valu 0 */ 13:printf("a = (5!= 5)\na =%d\n", a); 14: 15:a = (12 == 12)?1:0+ (5!= 1)?1:0;/* valu 1+1 */ 16:printf("\na = (12 == 12)?1:0+ (5!= 1)?1:0\na =%d\n", a); 17:exit(EXIT_SUCCESS); 18: } a a a a a a = = = = = = (5 == 5) 1 (5!= 5) 0 (12 == 12)+ (5!= 1) 2

http://fribok.blogspot.com/

Analyse Le rsultat de lexcution de ce programme peut vous paratre confus. Rappelez-vous, lerreur la plus courante avec les oprateurs de comparaison est dutiliser loprateur daffectation (=) en lieu et place de loprateur (==). La valeur de lexpression suivante est 5 (cette valeur est aussi stocke dans x) :
x = 5

Lexpression qui suit, au contraire, est value vrai ou faux (selon lgalit de x avec 5), mais elle ne change pas la valeur de x:
x == 5

Si vous crivez :
if (x = 5) printf("x est gal 5");

le message apparatra dans tous les cas, car lexpression sera toujours value comme vraie, quelle que soit la valeur de x. Vous comprenez maintenant pourquoi le programme du Listing 4.5 donne de telles valeurs a. En ligne 9, lexpression 5 ==5 tant toujours vraie, cest la valeur 1 qui est stocke dans a. En ligne 12, lexpression 5 diffrent de 5 tant fausse, cest la valeur 0 qui est attribue a. En ligne 15, loprateur de condition (voir plus loin) permet de renvoyer 1 ou 0 en fonction du test.

Hirarchie des oprateurs de comparaison


Comme pour les oprateurs mathmatiques, les oprateurs de comparaison sont traits dans un ordre donn. Lusage des parenthses permet de modier lordre de slection dans une instruction qui contient plusieurs oprateurs de comparaison. La hirarchie de tous les oprateurs du langage C vous sera fournie la n de ce chapitre. Les oprateurs de comparaison ont tous une priorit de traitement infrieure celle des oprateurs mathmatiques. Si vous crivez :
if (x+2 > y)

2 est ajout la valeur de x, et le rsultat est compar y. Linstruction suivante, quivalente la premire, est un bon exemple dutilisation des parenthses pour amliorer la lecture du code :
if ((x+2) > y)

http://fribok.blogspot.com/

Comme nous le montre le Tableau 4.6, il existe aussi deux niveaux de priorit pour le traitement des oprateurs de comparaison.
Tableau 4.6 : Hirarchie des oprateurs de comparaison du langage C

Oprateur < <= > >= != ==

Ordre de traitement
1 2

Linstruction :
x == y > z

est quivalente linstruction :


x == (y > z)

car lexpression y > z est la premire value et son rsultat, 0 ou 1, est affect la variable x. ne pas faire Introduire des instructions daffectation dans une instruction if. Cela peut induire en erreur la personne qui lira le code et elle risque de corriger en (==), en pensant une faute de programmation. Utiliser loprateur diffrent (!=) dans une instruction if qui a une clause else. Il est souvent plus clair dutiliser loprateur gal (==) avec cette clause. Par exemple, le code suivant :
if (x!= 5)

eils Cons

instruction1;
else

instruction2; scrirait mieux ainsi :


if (x == 5)

instruction2;
else

instruction1;

http://fribok.blogspot.com/

Les oprateurs logiques


Les oprateurs logiques de C permettent de vrier plusieurs comparaisons dans une mme question. Par exemple "sil est 7 heures du matin, un jour de semaine, et que je ne suis pas en vacances, faire sonner le rveil".
Tableau 4.7 : Les oprateurs logiques du langage C

Oprateur ET OU NON

Symbole && || !

Exemple exp1 && exp2 exp1 || exp2 !exp1

Tableau 4.8 : Utilisation des oprateurs logiques

Expression (exp1 && exp2) (exp1 || exp2) (!exp1)

Valeur
Vraie si exp1 et exp2 vraies. Sinon faux Vraie si exp1 vraie ou exp2 vraie. Faux si les deux expressions sont fausses. Faux si exp1 est vraie. Vraie si exp1 est fausse.

Les expressions qui contiennent des oprateurs logiques sont vraies ou fausses selon que leurs oprandes sont eux-mmes vrais ou faux.
Tableau 4.9 : Exemples dutilisation des oprateurs logiques

Expression (5 == 5) && (6!= 2) (5 > 1) || (6 < 1) (2 == 1) && (5 == 5) !(5 == 4)

Valeur
Vraie, car les deux oprandes sont vrais Vraie, car un oprande est vrai Faux, car un oprande est faux Vrai, car loprande est faux

Vous pouvez crer des expressions avec plusieurs oprateurs logiques. Par exemple, la question "x est-il gal 2, 3, ou 4?" se traduit par :
(x == 2) || (x == 3) || (x == 4)

http://fribok.blogspot.com/

Les oprateurs logiques offrent souvent plusieurs solutions pour poser une question. Si x est une variable entire, la question prcdente pourrait scrire des deux faons suivantes :
(x > 1) && (x < 5) (x >= 2) && (x <= 4)

Les valeurs VRAI/FAUX


Les expressions de comparaison du C ont la valeur 0 si elles sont fausses et diffrente de 0 si elles sont vraies. linverse, une valeur numrique sera interprte en vrai ou faux si elle se trouve dans une expression ou instruction qui attend une valeur logique (cest-dire vrai ou faux). La rgle est la suivante :

Une valeur de 0 signie faux. Une valeur diffrente de 0 signie vrai.

Voici un exemple dans lequel x sera toujours afch :


x = 125; if (x) printf("%d", x);

x tant diffrent de zro, linstruction if interprte lexpression (x) comme vraie. Vous pouvez gnraliser cette caractristique, car, pour une expression C, crire :
(expression)

est quivalent :
(expression!= 0)

Dans les deux cas, le rsultat est vrai si expression est diffrent de zro, et faux si expression a la valeur 0. En utilisant loprateur non (!), vous pouvez crire aussi :
(!expression)

qui est quivalent :


(expression == 0)

http://fribok.blogspot.com/

Hirarchie des oprateurs logiques


Les oprateurs logiques ont aussi leur priorit de traitement, entre eux ou en liaison avec les autres types doprateurs. Loprateur ! a la mme priorit que les oprateurs mathmatiques unaires ++ et . Il sera donc trait avant les oprateurs de comparaison et avant les oprateurs mathmatiques binaires. Au contraire, les oprateurs && et || seront traits aprs tous les autres oprateurs mathmatiques et de comparaison, && ayant une priorit suprieure celle de ||. Comme avec tous les autres oprateurs du langage C, les parenthses peuvent modier lordre de traitement. Examinons lexemple suivant. Vous voulez crire une expression logique qui effectue trois comparaisons : 1. a est-il plus petit que b? 2. a est-il plus petit que c? 3. c est-il plus petit que d? Vous voulez une expression logique qui soit vraie si la condition 3 est vraie et si lune des deux premires conditions est vraie. Vous pourriez crire :
a < b || a < c && c < d

Mais cette expression ne donnera pas le rsultat escompt. Loprateur && ayant une priorit suprieure ||, lexpression est lquivalent de :
a < b || (a < c && c < d)

Si (a < b) est vraie, lexpression prcdente est vraie quel que soit le rsultat de (a < c) et (c < d). Il faut crire :
(a < b || a < c) && c < d

qui force le traitement de || avant celui de &&. Cela est illustr par le Listing 4.6 qui value une expression crite de deux faons diffrentes. Les variables sont initialises pour que lexpression correcte soit gale 0 (fausse). Listing 4.6 : Hirarchie des oprateurs logiques
1: 2: 3: 4: 5: 6: 7: 8: 9: #include <stdio.h> #include <stdlib.h> /* Initialisation des variables. Notez que c nest pas */ /* infrieur d, ce qui est une des conditions tester. */ /* Lexpression complte doit finalement tre fausse. */ int a = 5, b = 6, c = 5, d = 1; int x;

http://fribok.blogspot.com/

Listing 4.6 : Hirarchie des oprateurs logiques (suite)


10: int main() 11: { 12:/* valuation de lexpression sans parenthses */ 13: 14:x = a < b || a < c && c < d; 15:printf("Sans parenthses lexpression a la valeur%d\n", x); 16: 17:/* valuation de lexpression avec parenthses */ 18: 19:x = (a < b || a < c) && c < d; 20:printf("Avec les parenthses lexpression a la valeur%d\n", x); 21:exit(EXIT_SUCCESS); 22: } Sans parenthses lexpression a la valeur 1 Avec des parenthses lexpression a la valeur 0

Analyse Ce programme initialise, en ligne 7, les quatre variables qui vont tre utilises dans les comparaisons. La ligne 8 dclare la variable x qui sera utilise pour stocker les rsultats. Les oprateurs logiques se trouvent en lignes 14 et 19. La ligne 14 nutilise pas les parenthses, le rsultat est donc fonction de la hirarchie des oprateurs et ne correspond pas au rsultat recherch. La ligne 19 utilise les parenthses pour changer lordre de traitement des oprateurs.

Les oprateurs daffectation composs


Ces oprateurs composs permettent dassocier une opration mathmatique binaire avec une opration daffectation. Pour, par exemple, augmenter la valeur de x de 5, il faut ajouter 5 x et stocker le rsultat dans la variable x:
x = x+5;

Loprateur compos permet dcrire :


x += 5;

Les oprateurs daffectation composs ont la syntaxe suivante (op reprsente un oprateur binaire) :
exp1 op= exp2;

qui est lquivalent de :


exp1 = exp1 op exp2;

http://fribok.blogspot.com/

Vous pouvez crer un oprateur compos partir des cinq oprateurs mathmatiques binaires. Le Tableau 4.10 vous donne quelques exemples.
Tableau 4.10 : Exemples doprateurs composs

Taper ceci...
x *= y y = z+1

... est quivalent ... x = x * y y = y z+1

a /= b x += y / 8 y%= 3

a = a / b x = x+y / 8 y = y% 3

Ces oprateurs fournissent une notation raccourcie agrable, surtout si la variable de gauche a un nom trs long. Comme pour toutes les autres instructions daffectation, ce type dinstruction est une expression dont la valeur est affecte la variable situe gauche. Si vous excutez linstruction suivante, les deux variables x et z auront la valeur 14 :
x = 12; z = x += 2;

Loprateur de condition
Loprateur de condition est le seul oprateur ternaire, ce qui signie quil prend trois oprandes. La syntaxe est la suivante :
exp1? exp2: exp3;

Si exp1 est vraie (cest--dire diffrente de zro), lexpression complte est value la valeur de exp2. Si exp1 est fausse, lexpression complte prendra la valeur de exp3. Lexemple suivant, par exemple, affecte la valeur 1 x si y est vraie, et stocke la valeur 100 dans x si y est fausse :
x = y? 1: 100;

De la mme faon, pour affecter z la valeur de la plus grande variable x ou y, vous pourriez crire :
z = (x > y)? x: y;

http://fribok.blogspot.com/

Cet oprateur a le mme mode de fonctionnement que linstruction if. Linstruction prcdente aurait pu scrire de cette faon :
if (x > y) z = x; else z = y;

Loprateur de condition ne peut pas remplacer toutes les instructions if, mais il a lavantage dtre plus concis. Vous pouvez lutiliser l ou vous ne pouvez pas utiliser if, comme dans une instruction printf():
printf( "La valeur la plus leve est%d", ((x>y)? x:y) );

La virgule
La virgule est souvent utilise en langage C comme une marque de ponctuation pour sparer les dclarations de variables, les arguments de fonctions, etc.. Dans certains cas, cette virgule agit comme un oprateur. Vous pouvez former une expression en sparant deux sousexpressions par une virgule. Le rsultat est le suivant :

Les deux expressions sont values en commenant par celle de gauche. Lexpression entire prend la valeur de lexpression de droite.

Linstruction qui suit attribue la valeur de b x, incrmente a, puis incrmente b:


x = (a++ , b++);

Loprateur ++ tant utilis en mode postx, la valeur de b avant son incrmentation est stocke dans x. Lusage des parenthses est obligatoire, car la virgule a une priorit infrieure celle du signe =. faire Utiliser (expression == 0) plutt que (!expression). Ces deux expressions ont le mme rsultat aprs compilation, mais la premire est plus facile lire. Utiliser les oprateurs && et || plutt que dimbriquer des instructions if. ne pas faire Confondre loprateur daffectation (=) avec loprateur gal (==).

eils Cons

http://fribok.blogspot.com/

Rorganisation de la hirarchie des oprateurs


Le Tableau 4.11 tablit un classement hirarchique de tous les oprateurs C dans un ordre dcroissant. Les oprateurs placs sur la mme ligne se situent au mme niveau hirarchique.
Tableau 4.11 : Hirarchie des oprateurs C

Niveau
1 2

Oprateurs () [] ! ~ ++ > . * (indirection) & (adresse-de) (type)

sizeof+ (unaire) - (unaire)


3 4 5 6 7 8 9 10 11 12 13 14 15

* (multiplication) /% + << >> < <= > >= ==!= & (ET bit bit) ^ | && || ?: = += , = *= /=%= &= ^= |= <<= >>=

() reprsente loprateur fonction; [] reprsente loprateur tableau.

ce Astu

Ce tableau permettra de vous familiariser avec un ordre hirarchique qui vous sera indispensable dans lavenir.

http://fribok.blogspot.com/

Rsum
Nous avons appris, dans ce chapitre, ce que reprsente une instruction du langage C, que les blancs de votre programme source sont ignors par le compilateur, et que le pointvirgule doit toujours terminer une instruction. Vous savez maintenant que vous pouvez utiliser un bloc (plusieurs instructions entre accolades) partout o lon peut utiliser une instruction simple. Beaucoup dinstructions sont constitues dexpressions et doprateurs. Rappelez-vous quune expression reprsente une valeur numrique. Une expression complexe est compose de plusieurs expressions simples appeles sous-expressions. Les oprateurs sont des symboles du langage C qui indiquent lordinateur deffectuer une opration sur une ou plusieurs expressions. Il existe des oprateurs unaires (qui agit sur une oprande unique), mais la majorit sont des oprateurs binaires qui oprent sur deux oprandes. Loprateur de condition est le seul oprateur ternaire (trois oprandes). Les oprateurs ont une hirarchie de traitement qui dtermine lordre dans lequel les oprations dune expression sont ralises. Les oprateurs sont diviss en trois catgories :

Les oprateurs mathmatiques qui effectuent des oprations arithmtiques sur leurs oprandes (laddition, par exemple). Les oprateurs de comparaison qui comparent leurs oprandes (plus grand que, par exemple). Les oprateurs logiques qui oprent sur des expressions vrai/faux. Noubliez pas que vrai et faux sont reprsents par 1 et 0 en langage C, et quune valeur diffrente de zro est interprte comme vraie.

Vous avez appris que linstruction if permet de contrler lexcution du programme en valuant des expressions de comparaison.

Q&R
Q Quels sont les effets des blancs et des lignes vides du chier source sur lexcution du programme ? R Tous les blancs (lignes, espaces, tabulations) permettent de rendre le programme source plus facile lire et comprendre. Au moment de la compilation, tous ces blancs sont ignors, ils nont donc aucune inuence sur lexcution du programme.

http://fribok.blogspot.com/

Q Faut-il choisir dcrire une instruction if compose ou des instructions if imbriques ? R Il faut simplier votre code source. Si vous imbriquez des instructions if, lvaluation se fait comme nous lavons vue dans ce chapitre. Si vous utilisez une instruction compose, les expressions ne sont values que si lexpression complte est fausse. Q Quelle est la diffrence entre un oprateur unaire et un oprateur binaire ? R Un oprateur unaire agit sur un seul oprande. Un oprateur binaire opre avec deux oprandes. Q Loprateur de soustraction est-il unaire ou binaire ? R Les deux ! Le compilateur saura lequel vous utilisez en fonction du nombre de variables utilises dans lexpression. Dans linstruction suivante il est unaire :
x = y;

Dans celle-ci, il est binaire :


x = a b;

Q Comment sont valus les nombres ngatifs : en vrai ou faux ? R Rappelez-vous, 0 est valu faux, toutes les autres valeurs sont values vraies. Les nombres ngatifs en font partie.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre. Essayez de comprendre les rponses fournies dans lAnnexe G avant de passer au chapitre suivant.

Quiz
1. Que fait linstruction suivante ?
x = 5+8;

2. Quest-ce quune expression ? 3. Quest-ce qui dtermine lordre de ralisation des oprations dans une expression qui contient plusieurs oprateurs ?

http://fribok.blogspot.com/

4. Si la variable x a la valeur 10, quelles sont les valeurs stockes dans x et a aprs lexcution de chacune de ces instructions (sparment) ?
a = x++; a = ++x;

5. Quelle est la valeur de lexpression 10% 3? 6. Quelle est la valeur de lexpression 5+3 * 8 / 2+2? 7. crivez lexpression de la question 6 avec des parenthses pour obtenir le rsultat 16. 8. Quelle valeur prend une expression fausse ? 9. Dans la liste suivante, quel oprateur est le plus prioritaire ? a) == ou <. b) * ou +. c) != ou ==. d) >= ou >. 10. Quest-ce quun oprateur daffectation compos et quel intrt a-t-il ?

Exercices
1. Le code qui suit nest pas rdig correctement. Saisissez-le et compilez-le pour voir le rsultat.
#include <stdio.h> #include <stdlib.h> int x,y;int main() { printf( "\nEntrez deux nombres");scanf( "%d%d",&x,&y);printf( "\n\n%d est plus grand",(x>y)?x:y); exit(EXIT_SUCCESS);}

2. Reprenez le code de lexercice 1 pour le rendre plus clair. 3. Transformez le Listing 4.1 pour compter en montant plutt quen descendant. 4. crivez une instruction if qui donne la valeur de x y si x se situe entre 1 et 20. Dans le cas contraire, ne pas changer la valeur de y. 5. Utilisez loprateur de condition pour faire lexercice prcdent. 6. Transformez les instructions suivantes pour nobtenir quune instruction if avec des oprateurs composs.
if (x < 1) if (x > 10) instruction;

http://fribok.blogspot.com/

7. Quelles sont les valeurs des expressions suivantes : a) (1+2 * 3). b) 10% 3 * 3 d) (5 == 5). e) (x = 5). 8. Si x = 4, y = 6, et z = 2, le rsultat aux questions suivantes est-il vrai ou faux : a) if (x == 4). b) if (x!= y c) if (z = 1). d) if (y). 9. crivez une instruction if pour savoir si une personne est un adulte (21 ans), mais pas une personne ge (65 ans). 10. CHERCHEZ LERREUR : Corrigez le programme suivant.
/* programme bogu */ #include <stdio.h> #include <stdlib.h> int x = 1: int main() { if (x = 1); printf("x gal 1"); sinon printf("x nest pas gal 1"); exit(EXIT_SUCCESS) }

(1+2).

c) ((1+2) * 3).

z).

http://fribok.blogspot.com/

Exemple pratique 2

Le nombre mystre
Voici la seconde section de ce type. Vous savez que son objectif est de prsenter un programme complet plus fonctionnel que les exemples des chapitres. Ce programme comporte quelques lments non encore tudis. Mais il ne devrait pas tre trop difcile comprendre. Prenez le temps de tester le code en le modiant ventuellement et en observant les rsultats. Attention aux fautes de frappe qui ne manqueront pas de provoquer des erreurs de compilation. Listing Exemple pratique 2 : trouver_nombre.c
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: /* Programme: trouver_nombre.c * Objectif: Ce programme choisit un nombre de faon alatoire * et demande lutilisateur de le retrouver * Retour: aucun */ #include <stdio.h> #include <stdlib.h> #include <time.h> #define NO #define YES 0 (!NO)

int main( void ) { int guess_value = -1; int number; int nbr_of_guesses; int done = NO; printf("Slection dun nombre alatoire\n");

http://fribok.blogspot.com/

Listing Exemple pratique 2 : trouver_nombre.c (suite)


22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: } /* le temps entre dans le calcul du nombre alatoire */ srand( time( NULL ) ); number = rand(); nbr_of_guesses = 0; while ( done == NO ) { printf("\nDonnez un nombre entre 0 et%d> ", RAND_MAX); scanf( "%d", &guess_value ); /* lecture du nombre */ nbr_of_guesses++; if ( number == guess_value ) { done = YES; } else if ( number < guess_value ) { printf("\nCe nombre est trop grand!"); } else { printf("\nCe nombre est trop petit!"); } } printf("\n\nFlicitations! Vous avez trouv en%d essais!", nbr_of_guesses); printf("\n\nLa rponse tait%d\n\n", number); exit(EXIT_SUCCESS);

Analyse Ce programme vous demande simplement de deviner le nombre choisi de faon alatoire par lordinateur. chaque essai, il vous indique si votre chiffre est suprieur ou infrieur la solution. Lorsque vous trouvez le rsultat, le programme vous indique le nombre de tentatives qui ont t ncessaires pour y arriver. Vous pouvez tricher en ajoutant une ligne qui afchera le nombre slectionn :
26: printf("le nombre choisi (rponse) est:%d", number);

Vous pourrez aussi contrler avec cette ligne le bon fonctionnement du programme. Noubliez pas de la supprimez si vous le transmettez des amateurs de jeux.

http://fribok.blogspot.com/

5
Les fonctions
Les fonctions sont au centre de la programmation du langage C et de la philosophie du dveloppement dans ce langage. Nous avons vu les fonctions de bibliothque qui sont fournies avec le compilateur. Ce chapitre traite des fonctions utilisateur qui sont cres par le programmeur. Aujourdhui, vous allez apprendre :

De quoi est constitue une fonction Les avantages de la programmation structure avec ces fonctions Comment crer une fonction Les dclarations de variables locales dune fonction Comment transmettre une valeur de la fonction vers le programme Comment passer des arguments une fonction

http://fribok.blogspot.com/

Quest-ce quune fonction ?


Ce chapitre aborde les fonctions sous deux angles, en les dnissant et en montrant quoi elles servent.

Dnition
Une fonction est un bloc de code C indpendant, rfrenc par un nom, qui ralise une tche prcise et qui peut renvoyer une valeur au programme qui la appele. Examinons cette dnition :

Une fonction est rfrence par un nom. Ce nom est unique et en lintroduisant dans le source de votre programme, vous pouvez excuter le code de la fonction. Une fonction peut tre appele par une autre fonction. Une fonction est indpendante. Une fonction peut effectuer sa tche avec ou sans changes avec une autre partie du programme. Une fonction ralise une tche particulire. La tche est lunit de base du travail ralis par le programme. Cela peut tre lenvoi dune ligne de texte vers limprimante, un tri, ou le calcul dune racine carre. Une fonction peut renvoyer une valeur au programme appelant. Quand ce programme appelle la fonction, le code de cette fonction est excut. Ces instructions peuvent renvoyer une information au programme.

Exemple de fonction
Listing 5.1 : Ce programme emploie une fonction utilisateur pour calculer le cube dun nombre
1: /* Exemple dune fonction simple */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: long cube(long x); 5: 6: long input, reponse; 7: 8: int main() 9: { 10:printf("Entrez une valeur entire : "); 11:scanf("%d", &input); 12:reponse = cube(input);

http://fribok.blogspot.com/

13:/* Note:%ld est la spcification de conversion dun entier long */ 14:printf("\n\nLe cube de%ld est%ld\n.", input, reponse); 15:exit(EXIT_SUCCESS); 16: } 17: 18: long cube(long x) 19: { 20:long x_cube; 21: 22:x_cube = x * x * x; 23:return x_cube; 24: } Entrez un nombre entier: 100 Le cube de 100 est 1000000 Entrez un nombre entier: 9 Le cube de 9 est 729 Entrez un nombre entier: 3 Le cube de 3 est 27

ntion Atte

Lanalyse suivante ne porte pas sur la totalit du programme, mais se concentre sur les lments du programme directement en relation avec la fonction.

Analyse La ligne 4 contient le prototype (dclaration) de la fonction qui reprsente un modle pour une fonction qui apparatra plus loin dans le programme. Ce prototype contient le nom de la fonction, la liste des variables qui lui seront transmises, et ventuellement le type de variable que la fonction renverra. La ligne 4 nous indique que la fonction sappelle cube, quelle utilise une variable de type long, et quelle renverra une variable de type long. Les variables qui sont transmises la fonction sont des arguments et apparaissent entre parenthses derrire le nom de la fonction. Dans notre exemple, largument de la fonction est long x. Le mot cl situ avant le nom indique le type de variable renvoy par la fonction. Dans notre cas, cest un type long. La ligne 12 appelle la fonction cube et lui transmet en argument la variable input. La valeur renvoye par la fonction est stocke dans la variable reponse. Ces deux variables sont dclares en ligne 6 avec le type long ce qui correspond bien au prototype de la ligne 4. Les lignes 18 24, qui constituent la fonction cube elle-mme, sont appeles dnition de la fonction. La fonction commence par un en-tte en ligne 18 qui indique son nom (dans notre exemple cube). Cet en-tte dcrit aussi le type de donne qui sera renvoye et les

http://fribok.blogspot.com/

arguments. Vous pouvez remarquer que len-tte de fonction est identique au prototype (le point-virgule en moins). Les lignes 20 23 reprsentent le corps de la fonction ; il est encadr par des accolades. Il contient des instructions, comme celle de la ligne 22, qui sont excutes chaque fois que la fonction est appele. La ligne 20 est une dclaration de variable comme nous en avons dj vu, une exception prs : cest une variable locale. Les variables locales, qui sont traites au Chapitre 12, sont dclares lintrieur dune fonction. La ligne 23 indique la n de la fonction et renvoie une valeur au programme appelant. Dans notre cas, cest la valeur de x cube qui est transmise. Si vous comparez la structure de la fonction avec celle de la fonction main(), vous ne trouverez pas de diffrence. Comme printf() ou scanf() qui sont des fonctions de bibliothque, toutes les fonctions peuvent recevoir des arguments et renvoyer une valeur au programme qui les a appeles.

Fonctionnement
Les instructions dune fonction dans un programme ne sont excutes que lorsquelles sont appeles par une autre partie de ce programme. Quand la fonction est appele, le programme lui transmet des informations sous la forme darguments. Un argument est une donne de programme dont la fonction a besoin pour excuter sa tche. La fonction sexcute puis le programme reprend partir de la ligne qui contient lappel en rcuprant ventuellement une valeur de retour. La Figure 5.1 reprsente un programme qui appelle trois fonctions. Les fonctions peuvent tre appeles autant de fois que ncessaire et dans nimporte quel ordre.
Figure 5.1 Quand un programme appelle une fonction, les instructions de la fonction sexcutent puis le programme reprend la main pour la suite de son excution.
fonct1 { }

Programme principal
main () { appel fonct1 ... appel fonct2 ... appel fonct3 }

fonct2 { }

fonct3 { }

http://fribok.blogspot.com/

Fonctions
Prototype de la fonction
type_retour nom_fonction (type_arg nom1, ..., type_arg nomn);

Dnition de la fonction
type_retour nom_fonction (type_arg nom1, ..., type_arg nomn) ; { /* instructions; */ }

Le prototype de la fonction fournit au compilateur la description dune fonction qui est dnie plus loin dans le programme. Cette description comprend le nom de la fonction, le type de valeur (type retour) qui sera renvoye la n de lexcution de la fonction et les types darguments (type arg) qui lui seront transmis. Il peut ventuellement contenir le nom des variables qui seront transmises et il se termine toujours par un point-virgule. La dnition de la fonction est la fonction, cest--dire le code qui sera excut. La premire ligne, l en-tte de la fonction, est identique au prototype, lexception du pointvirgule. Cet en-tte doit obligatoirement contenir le nom des variables arguments qui tait en option dans le prototype. Il est suivi du corps de la fonction, les instructions entre accolades. Si le type retour nest pas void, il faut une instruction return qui renvoie une valeur correspondant au type retour. Exemples de prototypes
double carr (double nombre); void impression_rapport (int nombre_rapport); int choix_menu (void);

Exemples de dnitions
double carr (double nombre)/* en-tte de fonction */ {/* accolade de dbut */ return (nombre * nombre);/* corps de la fonction */ }/* accolade de fin */ impression_rapport (int nombre_rapport) { if (nombre_rapport == 1) puts ("Impression rapport 1"); else puts("pas dimpression du rapport 1"); }

http://fribok.blogspot.com/

Les fonctions et la programmation structure


En utilisant des fonctions dans votre programme vous pratiquez la programmation structure. Cela signie que les diffrentes tches du programme sont ralises par des portions de code indpendantes : les fonctions.

Avantages de la programmation structure


La programmation structure a deux avantages :

Il est plus facile dcrire un programme structur, car des problmes de programmation complexes peuvent tre diviss en tches plus simples. Chacune de ces tches est ralise par une fonction dont le code et les variables sont indpendants du reste du programme. Un programme structur est plus facile corriger. En effet, lerreur pourra facilement tre localise dans une partie spcique du code (celle de la fonction qui ne sexcute pas correctement).

Ce type de programmation peut vous faire gagner du temps. En effet, une fonction que vous aurez crite dans un programme pour raliser une certaine tche, pourra facilement tre utilise dans un autre programme pour raliser la mme tche. Si celle-ci est lgrement diffrente, il sera plus facile de la modier que den crer une nouvelle.

tude dun programme structur


Pour crire un programme structur, vous devez faire une tude pralable avant de crer la premire ligne de code. Cette tude doit tre compose de la liste des tches raliser par le programme. Par exemple, pour crire un programme de gestion de vos adresses, voici les tches que devrait pouvoir faire ce programme :

Saisir les nouveaux noms et adresses. Modier un enregistrement. Trier les noms de famille. Imprimer les noms et adresses sur des enveloppes.

Cette liste permet de partager le programme en quatre fonctions principales. Vous pouvez maintenant dcomposer ces tches en sous-tches plus simples. "Saisir les nouveaux noms et adresses" peut ainsi devenir :

Lire la liste des adresses existantes.

http://fribok.blogspot.com/

Demander lutilisateur de taper une ou plusieurs nouvelles adresses. Ajouter les nouveaux enregistrements. Sauvegarder la nouvelle liste sur disque.

De la mme faon, vous pouvez dcomposer "Modier un enregistrement" :


Lire la liste des adresses existantes. Modier un ou plusieurs enregistrements. Sauvegarder la nouvelle liste sur disque.

Ces deux listes ont deux sous-tches en commun : celle qui lit et celle qui sauvegarde. Vous pouvez crire une fonction pour "lire les adresses existantes sur disque" et cette fonction sera appele par chacune des fonctions "Saisir les nouveaux noms et adresses" et "Modier un enregistrement". Le raisonnement est le mme pour "Sauvegarder la nouvelle liste sur disque". En identiant ainsi des parties du programme qui ralisent la mme tche, vous pouvez crire des fonctions qui seront appeles plusieurs fois par le programme. Vous gagnez du temps et votre programme est plus efcace. Comme le montre la gure suivante, cette mthode de programmation conduit une structure de programme hirarchique.
Figure 5.2 Un programme structur est organis de faon hirarchique.
Saisie Mise jour

main

Tri

Impression

Lire

Modifier

Sauvegarder

Lapproche top-down
Avec la programmation structure, les programmeurs adoptent une approche top-down (de haut en bas). Cela est illustr par la Figure 5.2 ou la structure du programme ressemble

http://fribok.blogspot.com/

un arbre invers. En gnral, les tches importantes sont ralises au bout des "branches", les autres fonctions sont l pour orienter lexcution du programme vers ces fonctions. Par ce fait, beaucoup de programmes C ont trs peu de code dans la partie principale main(), et une partie de code importante pour les fonctions. Vous trouverez dans la partie main quelques lignes dinstructions dont le rle se limitera aiguiller lexcution du programme vers les fonctions. Ces lignes reprsentent souvent un menu dans lequel lutilisateur choisit la tche quil veut raliser. Chaque partie de ce menu utilise une fonction diffrente. Le Chapitre 13, avec linstruction switch, vous apprendra crer un bon systme base de menus.
eils Cons

faire tablir le plan du programme avant de commencer coder. En dterminant lavance la structure de votre programme, vous gagnerez du temps au dveloppement et la correction. ne pas faire Essayer de tout faire avec une seule fonction. Une fonction doit excuter une seule tche, comme lire un chier ou sauvegarder des donnes.

criture dune fonction


La premire tape de lcriture dune fonction consiste savoir ce que doit faire cette fonction. La suite ne reprsente pas de difcults particulires.

En-tte
La premire ligne dune fonction est len-tte de la fonction. Il est constitu de trois lments qui ont chacun un rle particulier.
Figure 5.3 Les trois composants de len-tte de fonction.
Type de valeur renvoye par la fonction Liste des paramtres

type nom_fonction(parm1,.

Nom de la fonction

http://fribok.blogspot.com/

Type de la valeur renvoye


Le type de la valeur renvoye indique le type de donne que la fonction retournera au programme appelant. Ce type peut tre : char, int, long, float, ou double. Vous pouvez aussi crer une fonction qui ne retourne pas de valeur en utilisant le type de valeur renvoye void. Voici quelques exemples :
int fonc1(...)/* renvoie une donne de type int. */ float fonc2(...)/* renvoie une donne de type float. */ void fonc3(...)/* ne renvoie aucune donne. */

Nom
Le nom dune fonction doit suivre les mmes rgles que les noms de variables C (voir Chapitre 3) et il doit tre unique (vous ne pouvez pas appeler une variable ou une autre fonction par le mme nom).

Liste des paramtres


Beaucoup de fonctions utilisent des arguments, et elles ont besoin de connatre le type de donne quelles vont recevoir. Vous pouvez transmettre une fonction nimporte quel type de donne C en lindiquant dans len-tte de cette fonction avec la liste de paramtres. chaque argument transmis vers la fonction doit correspondre une entre dans la liste de paramtres. Voici, par exemple, len-tte de la fonction du Listing 5.1 :
long cube (long x)

La liste de paramtres contient long x ce qui indique la fonction quelle recevra un paramtre de type long reprsent par la variable x. Si la liste contient plusieurs paramtres, ils sont spars par une virgule. Examinons len-tte suivant :
void fonction1 (int x, float y, char z)

La fonction va recevoir trois arguments : x de type int, y de type float, et z de type char. Une fonction qui ne doit pas recevoir de paramtre a une liste darguments qui contient void:
void fonction2 (void)

ntion Atte

Il ne faut pas mettre de point-virgule la n de votre en-tte de fonction, sinon le compilateur gnrera un message derreur. Il ne faut pas confondre paramtre et argument. Un paramtre est une entre de len-tte de la fonction, il "annonce" largument. Les paramtres ne peuvent changer pendant lexcution du programme.

http://fribok.blogspot.com/

Un argument est une donne transmise la fonction par le programme appelant. Chaque fois que la fonction sera appele, le programme pourra lui transmettre des valeurs darguments diffrents. Par contre, le nombre et le type des arguments transmis ne doivent pas changer. Largument est rfrenc par le nom correspondant dans la liste de paramtres. Listing 5.2 : Diffrence entre argument et paramtre
1: /* Ce programme montre la diffrence entre paramtre et argument 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: float x = 3.5, y = 65.11, z; 6: 7: float moitie_de(float k); 8: 9: int main() 10: { 11: /* Dans cet appel, x est largument de moitie_de(). */ 12:z = moitie_de(x); 13:printf("La valeur de z =%f\n", z); 14: 15: /* Dans cet appel,y est largument de moitie_de(). */ 16:z = moitie_de(y); 17:printf("La valeur de z =%f\n", z); 18:exit(EXIT_SUCCESS); 19: } 20: 21: float moitie_de(float k) 22: { 23:/* k est le paramtre. Chaque fois que moitie_de est */ 24:/* appele, k prend la valeur qui a t passe en argument */ 25: 26:return (k/2); 27: } La valeur de z = 1.750000 La valeur de z = 32.555000 */

Figure 5.4 Schma des relations entre arguments et paramtres.

Premier appel de la fonction

z=moiti_de(x);

3,5

float moiti_de(float k)

Second appel de la fonction

z=moiti_de(y);

65,11

float moiti_de(float k)

http://fribok.blogspot.com/

Analyse Examinons le programme du Listing 5.2. Le prototype de la fonction moitie de() se trouve en ligne 7. Les lignes 12 et 16 appellent cette fonction dont les instructions sont en lignes 21 27. La ligne 12 envoie largument x, qui contient la valeur 3,5 ; la ligne 16 envoie largument y, qui contient la valeur 65,11. Les rsultats donns par le programme donnent bien la moiti de ces deux valeurs. Les valeurs contenues dans x et y sont transmises par lintermdiaire de largument k de moitie de(). On a fait, en fait, une copie de x en k puis une copie de y en k. La fonction a ensuite retourn ces valeurs divises par deux.
eils Cons

faire Choisir des noms de fonctions qui indiquent ce quelles font. ne pas faire Transmettre une fonction une donne dont elle na pas besoin. Transmettre plus (ou moins) darguments quil ny a de paramtres. En langage C, le nombre darguments transmis doit correspondre exactement au nombre de paramtres.

Instructions
Le corps de la fonction se trouve entre accolades la suite de len-tte. Quand la fonction est appele, lexcution commence la premire instruction du corps de la fonction et se termine la premire instruction return rencontre ou laccolade de n.

Les variables locales


Il est possible de dclarer des variables internes la fonction, ce sont les variables locales. Elles sont particulires cette fonction et diffrentes de variables du mme nom qui pourraient se trouver dans une autre partie du programme. La dclaration dune variable locale suit les mmes principes que ceux dune variable standard qui ont t noncs dans le Chapitre 3. Vous pouvez les initialiser au moment de la dclaration et elles peuvent tre nimporte quel type de variable C. Voici un exemple de quatre variables dclares dans une fonction :
int fonction1(int y) { int a, b = 10; float taux; double cout = 12.55; /* instructions */. }

http://fribok.blogspot.com/

Cette dclaration cre les variables locales a, b, taux, et cout qui seront utilises par le code de la fonction. Les paramtres de la fonction sont considrs comme des dclarations de variable. Si la liste nest pas vide, ces variables sont donc disponibles pour les instructions qui suivent. Le Listing 5.3 vous donne la dmonstration de lindpendance des variables locales vis vis des autres variables du programme. Listing 5.3 : Utilisation de variables locales
1: /* Dmonstration de lindpendance des variables locales. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int x = 1, y = 2; 6: 7: void demo(void); 8: 9: int main() 10: { 11:printf("Avant dappeler demo(), x =%d et y =%d.\n", x, y); 12:demo(); 13:printf("Aprs lappel de demo(), x =%d et y =%d\n.", x, y); 14:exit(EXIT_SUCCESS); 15: } 16: 17: void demo(void) 18: { 19:/* Dclaration et initialisation de deux variables locales. */ 20: 21:int x = 88, y = 99; 22: 23:/* Affichage de leur valeur. */ 24: 25:printf("Dans la fonction demo(), x =%d et y =%d.\n", x, y); 26: } Avant dappeler demo(), x = 1 et y = 2. Dans la fonction demo(), x = 88 et y = 99. Aprs lappel de demo(), x = 1 et y = 2.

Analyse La ligne 5 de ce programme dclare les variables x et y. Elles sont dclares en dehors de toute fonction, ce sont donc des variables globales. La ligne 7 contient le prototype de la fonction demo(). Cette ligne commence par void qui indique que la fonction ne travaille pas avec des paramtres. Le deuxime void qui remplace le type de paramtre indique que la fonction ne retourne aucune valeur au programme appelant. La fonction principale

http://fribok.blogspot.com/

main() commence en ligne 9 : la fonction printf() de la ligne 11 afche les valeurs de x et y puis la fonction demo() est appele. demo() dclare ses versions locales de x et y en ligne 21. La ligne 24 dmontre que les valeurs des variables locales supplantent celles des variables du programme. Aprs lappel de la fonction, la ligne 13 afche de nouveau x et y qui sont revenues leur valeur initiale. Nous venons de vous dmontrer que les variables locales x et y de la fonction taient totalement indpendantes des variables globales x et y des autres parties du programme. Lutilisation des variables dans une fonction doit suivre trois rgles :

Pour utiliser une variable dans une fonction, vous devez la dclarer dans len-tte ou le corps de la fonction. Pour que la fonction puisse recevoir une donne du programme appelant, celle-ci doit tre transmise en argument. Pour que le programme appelant puisse recevoir une valeur retour de la fonction, cette valeur doit tre explicitement renvoye par la fonction.

Crer des variables locales est une des faons de rendre les fonctions indpendantes. Une fonction peut effectuer toutes sortes de manipulations de donnes avec des variables locales et cela ne pourra pas affecter une autre partie du programme.

Les instructions
Il ny a aucune contrainte pour lutilisation des instructions dans une fonction. La seule chose que lon ne puisse pas faire dans une fonction est de dnir une autre fonction. Vous pouvez utiliser toutes les autres instructions du langage C en incluant les boucles (traites au Chapitre 6), les instructions if, ou les instructions daffectation. Il nexiste pas non plus de contrainte de taille , mais en programmation structure une fonction effectue une tche simple. Si la fonction que vous crez est longue, vous essayez peut-tre dexcuter une tche trop complexe pour une seule fonction. Celle-ci pourrait tre dcompose en plusieurs fonctions plus petites. En gnral, la taille maximum dune fonction est de 25 30 lignes de code. Certaines seront plus longues, dautres nauront besoin que de quelques lignes. Lorsque vous aurez une bonne exprience de programmation, vous saurez si une fonction doit tre divise en plusieurs plus petites ou non.

Comment renvoyer une valeur


Le mot cl return permet de renvoyer une valeur au programme appelant. Quand une instruction return est rencontre au cours de lexcution de la fonction, celle-ci est value et la valeur trouve est transmise au programme.

http://fribok.blogspot.com/

Examinons lexemple suivant :


int fonct1(int var) { int x; /* instructions... */ return x; }

Quand cette fonction est appele, toutes les instructions sexcutent jusqu linstruction return qui renvoi la valeur x au programme appelant. Lexpression qui suit le mot cl return peut tre nimporte quelle expression du langage C. Une fonction peut contenir plusieurs instructions return. Cest la premire qui est excute qui pourra provoquer le retour vers le programme. Listing 5.4 : Utilisation de plusieurs instructions return dans une fonction
1: /* Exemple de plusieurs instructions return dans une fonction. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int x, y, z; 6: 7: int larger_of(int a, int b); 8: 9: int main() 10: { 11:puts("Entrez deux valeurs entires diffrentes : "); 12:scanf("%d%d", &x, &y); 13: 14:z = larger_of(x,y); 15: 16:printf("\nLa valeur la plus grande est%d.", z); 17:exit(EXIT_SUCCESS); 18: } 19: 20: int larger_of(int a, int b) 21: { 22:if (a > b) 23:return a; 24:else 25:return b; 26: } Entrez 2 valeurs entires diffrentes: 200300 La valeur la plus grande est 300. Entrez 2 valeurs entires diffrentes: 300 200 La valeur la plus grande est 300.

http://fribok.blogspot.com/

Analyse Le chier en-tte stdio.h est appel ligne 3 pour permettre les entres/sorties demandes par le programme. La ligne 7 est le prototype de la fonction larger of(). Vous pouvez remarquer quelle reoit deux variables int comme paramtres et quelle renverra une valeur entire. Cette fonction est appele en ligne 14 avec x et y. Elle compare a et b en ligne 22. Si a est plus grand que b, la ligne 23 excute linstruction return et la fonction se termine : les lignes 24 et 25 seront ignores. Si b est plus grand que a, lexcution de la fonction se poursuit la ligne 24 avec la clause else et la ligne 25 excute la seconde instruction return. Cette fonction possde bien plusieurs instructions return qui sont excutes en fonction de la valeur des variables transmises lors de lappel. La dernire remarque faire sur ce programme concerne la ligne 11. Elle contient la nouvelle fonction puts() (lire put string, en franais envoi chane de caractres). Cette fonction, qui est traite au Chapitre 10, envoi simplement une chane de caractres vers la sortie standard (en gnral lcran). Retenez que la valeur de la variable renvoye par une fonction doit correspondre au type de variable dclar dans len-tte de la fonction et dans le prototype. En programmation structure, vous devez avoir seulement une entre et une sortie dans une fonction. Cela signie que vous devez vous efforcer dobtenir une seule instruction return. Un programme sera cependant plus facile interprter avec plusieurs de ces instructions. Dans ce cas, la priorit sera donne linterprtation.

Info

Prototype
Un programme peut contenir un prototype pour chaque fonction quil utilise. La ligne 4 du Listing 5.1 vous donne un exemple de prototype. Quest-ce quun prototype et quoi sert-il ? Nous avons vu que le prototype est identique len-tte de la fonction et quil se termine par un point-virgule. Il contient des informations sur le nom, les paramtres et le type de donne renvoye par la fonction. Ces informations sont destines au compilateur. Il pourra ainsi vrier, chaque appel de la fonction, que vous avez transmis le bon nombre et le bon type de paramtres, et que la valeur de retour uti-lise est correcte. Si ce contrle choue, le compilateur envoi un message derreur. Le prototype est obligatoire si la fonction est dnie aprs un appel celle-ci. Sinon, le compilateur nen a pas connaissance et signale une erreur. Un prototype de fonction peut ne pas tre strictement identique len-tte de la mme fonction. Le nom des paramtres peut tre diffrent du moment que le nombre, le type, et lordre

http://fribok.blogspot.com/

est respect. Le plus simple pour le programmeur reste bien sr dutiliser le copier-coller de lditeur de texte pour copier len-tte de la fonction et crer le prototype en ajoutant le point-virgule. Le risque derreur sera rduit et votre programme gagnera en clart. Pour des raisons pratiques, il est prfrable de grouper tous les prototypes au mme endroit, avant le dbut de la fonction principale main() voire dans un chier den-ttes (extension .h) inclure avec #include.
eils Cons

faire Utiliser des variables locales quand cest possible. Crer des fonctions qui excutent une seule tche. ne pas faire Renvoyer une valeur dont le type ne correspond pas celui de la fonction. crire des fonctions trop longues : essayez de les dcouper en plusieurs tches plus petites. Crer des fonctions avec plusieurs instructions return alors que ce nest pas ncessaire.

Passage darguments une fonction


Les arguments sont transmis une fonction au moyen de la liste entre parenthses qui suit le nom de la fonction. Le nombre et le type de ces arguments doivent correspondre aux indications de rendu de len-tte et du prototype de la fonction. Si vous essayez de transmettre un mauvais nombre ou un type incorrect darguments, le compilateur le dtectera partir des informations fournies par le prototype. Dans le cas o une fonction reoit plusieurs valeurs, les arguments qui sont lists dans lappel de la fonction sont attribus dans le mme ordre aux paramtres de cette fonction comme lindique la Figure 5.5.

Un argument peut tre nimporte quelle expression du langage C : une constante, une variable, une expression mathmatique ou logique, ou une autre fonction (avec une valeur de retour). Par exemple, si moitie(), carre(), et troisieme() sont des fonctions qui renvoient une valeur vous pouvez crire :
x = moitie(troisieme(carre(moitie(y))));

http://fribok.blogspot.com/

Figure 5.5 Les arguments sont attribus dans lordre aux paramtres.

Appel de la fonction

fonct1(a,b,c);

En-tte de la fonction

void fonct1(int x,in

La premire fonction appele par le programme sera moitie() qui ont passera largument y. La valeur de retour sera transmise la fonction carre() puis la fonction troi sieme() sera appele en lui transmettant la valeur renvoye par carre(). Enn, la fonction moitie() sera de nouveau appele avec la valeur de retour de troisieme() en argument. Cest la valeur renvoye par moitie() qui sera nalement attribue x. Le code suivant est quivalent lexemple prcdent :
a b c x = = = = moitie(y); carre(a); troisieme(b); moitie(c);

Appel dune fonction


Il existe deux faons dappeler une fonction. La premire consiste utiliser son nom suivi de la liste darguments entre parenthses, dans une instruction. Si la fonction a une valeur de retour, elle sera ignore.
wait(12);

La seconde mthode ne concerne que les fonctions qui renvoient une valeur. Ces fonctions tant values leur valeur de retour, elles font partie des expressions du langage C et peuvent donc tre utilises comme tel :
printf("La moiti de%d est%d.", x, moitie_de(x));

Lexcution de cette instruction commence par lappel de la fonction moitie de() avec la valeur de x. La fonction printf() est ensuite excute avec les valeurs x et moitie de(x). Voici un autre exemple de plusieurs fonctions utilises comme des expressions :
y = moitie_de(x)+ moitie_de(z);

qui est lquivalent de :


a = moitie_de(x); b = moitie_de(z); y = a+b;

http://fribok.blogspot.com/

Ces deux derniers exemples vous montrent comment utiliser les valeurs renvoyes par les fonctions.
if (moitie_de(x) > 10) { /* instructions */ }

Si la valeur calcule par la fonction remplit la condition, linstruction if est vrai et les instructions sont excutes. Dans le cas contraire, les instructions ne sont pas excutes.
if (processus()!= OK) { /* instructions *//* traitement des erreurs */ }

Dans cet exemple, la valeur renvoye par le processus est contrle pour savoir si lexcution de ce processus sest droule correctement. Dans le cas contraire, les instructions traiteront les erreurs. Cette mthode est souvent employe pour lire des chiers, comparer des valeurs et allouer de la mmoire. Le compilateur gnrera un message derreur si vous tentez dutiliser une fonction avec un type retour void comme une instruction.
eils Cons

faire Transmettre des paramtres aux fonctions pour rendre leur code facilement rutilisable. Tirer parti de la possibilit de remplacer une expression par une fonction. ne pas faire Rendre une instruction illisible en y introduisant trop de fonctions.

Rcurrence
Lorsquune fonction sappelle elle-mme de faon directe ou indirecte, on parle de rcurrence. Dans une rcurrence indirecte, une fonction appelle une autre fonction qui appelle son tour la premire. Le langage C permet ce schma qui peut se rvler trs utile dans certaines circonstances. Par exemple, la rcurrence peut tre utilise pour calculer le factoriel dun nombre. Le factoriel dun nombre x se note x! et se calcule de la faon suivante :
x! = x * (x1) * (x2) * (x3) *,etc. * (2) * 1

http://fribok.blogspot.com/

Voici une autre mthode pour calculer x!:


x! = x * (x1)!

ou
(x1)! = (x1) * (x2)!

Vous pouvez continuer calculer de faon rcurrente jusqu la valeur 1. Le programme du Listing 5.5 utilise une fonction rcurrente pour calculer les factorielles. Le programme nutilisant que les entiers non signs, la valeur transmise au programme sera limite 8. Le factoriel de 9 ou de nombres plus grands sort des limites autorises pour les entiers. Listing 5.5 : Calcul des factorielles avec une fonction rcurrente
1: /* Exemple de fonction rcurrente. Calcul de la factorielle dun nombre 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: unsigned int f, x; 6: unsigned int factorielle(unsigned int a); 7: 8: int main() 9: { 10:puts("Entrez une valeur entire entre 1 et 8: "); 11:scanf("%d", &x); 12: 13:if(x > 8 || x < 1) 14:{ 15: printf("On a dit entre 1 to 8!"); 16:} 17:else 18:{ 19: f = factoriel(x); 20: printf("Factorielle%u gal%u\n", x, f); 21:} 22:exit(EXIT_SUCCESS); 23: } 24: 25: unsigned int factorielle(unsigned int a) 26: { 27:if (a == 1) 28: return 1; 29:else 30:{ 31: a *= factorielle(a1); 32: return a; 33:} 34: }

http://fribok.blogspot.com/

Entrez une valeur entire entre 1 et 8: 6 Factorielle 6 gal 720

Analyse La premire partie du programme ressemble celles des programmes que nous avons dj tudis. Les commentaires sont en ligne 1, lappel du chier en-tte en ligne 3 et la ligne 5 contient la dclaration de deux valeurs entires non signes. Le prototype de la fonction factorielle() se trouve en ligne 6. La fonction principale main() est constitue des lignes 8 23. Les lignes 10 et 11 permettent de rcuprer le nombre choisit par lutilisateur. Linstruction if des lignes 13 21 est intressante. Elle permet de contrler la valeur entre par lutilisateur. Si elle est plus grande que 8, un message derreur est envoy. Sinon, le calcul de la factorielle se fait en ligne 19 et la ligne 20 afche le rsultat. Traitez les erreurs de cette faon chaque fois que vous suspectez un problme (comme la taille dun nombre par exemple). Notre fonction rcurrente se trouve lignes 25 34. La valeur qui lui est transmise est attribue a et contrle en ligne 27. Si la valeur de a est 1, le programme renvoi la valeur 1. Si la valeur de a est diffrente de 1, on attribue a la valeur de a * facto rielle(a 1). Le programme appelle la fonction factoriel de nouveau, mais cette fois la valeur de a est (a 1). Si (a 1) est diffrent de 1, factorielle() est appel de nouveau avec ((a 1) 1). Le processus se poursuit jusqu ce que lordre if de la ligne 27 soit vrai. faire Vous exercer la rcurrence avant de lutiliser. ne pas faire Ne pas utiliser la rcurrence sil y a plusieurs itrations (rptition dune instruction). En effet, la rcurrence mobilise beaucoup de ressources pour que la fonction puisse se grer.

eils Cons

Le placement des fonctions


Les dnitions de fonctions peuvent se placer dans le mme chier source que la fonction principale main() et aprs la dernire instruction de celle-ci. Vous pouvez sauvegarder vos fonctions utilisateur dans un chier spar de celui qui contient la fonction main(). Cette technique est trs utile dans le cas dun programme trs

http://fribok.blogspot.com/

long ou si vous voulez utiliser cette mme srie de fonctions dans un autre programme (voir Chapitre 21).
Figure 5.6 Structure dun programme qui utilise des fonctions.
/* Dbut de code source */ ... prototype des fonctions ... int main() { ... ... } fonct1() { ... } fonct2() { ... } Fin du code source */

/*

Rsum
Les fonctions sont une partie importante de la programmation en langage C. Le code qui les reprsente est indpendant du programme. Le rle dune fonction est dexcuter une tche particulire : quand votre programme a besoin de raliser cette tche, il appelle la fonction. La programmation structure sappuie sur lutilisation de ces fonctions an dobtenir un code modulaire et une approche "top-down". Les programmes ainsi dvelopps sont plus performants et faciles utiliser. Une fonction est constitue dun en-tte et dun corps. Len-tte contient le nom de la fonction, les paramtres et le type de valeur quelle va renvoyer. Le corps contient les dclarations de variables locales et les instructions qui seront excutes lappel de la fonction. Les variables locales, dclares dans la fonction, sont compltement indpendantes des autres variables du programme.

Q&R
Q Comment une fonction peut-elle renvoyer plusieurs valeurs ? R Vous aurez souvent besoin de renvoyer plusieurs donnes partir dune seule fonction. Ce sujet est couvert par le Chapitre 18 qui vous donnera plus dinformations sur les fonctions.

http://fribok.blogspot.com/

Q Comment choisir un bon nom de fonction ? R Le bon choix pour un nom de fonction est celui qui dcrira le mieux ce que fait la fonction. Q Quand les variables sont dclares en dbut de programme, avant la fonction main(), on peut les utiliser tout moment, sauf les variables locales qui sont utilises dans les fonctions. Pourquoi ne pas faire toutes les dclarations avant main()? R Le Chapitre 12 vous donnera de plus amples informations concernant la porte des variables. Q Comment peut-on employer la rcurrence ? R La fonction factorielle est un premier exemple dutilisation de rcurrence. Elle est souvent utilise pour calculer des statistiques. La rcurrence est une sorte de boucle qui, au contraire des autres boucles que vous tudierez dans le prochain chapitre, cre une nouvelle srie de variables chaque appel de la fonction. Q La fonction main() doit-elle tre la premire apparatre dans le programme ? R Non. En langage C, la fonction main() est la premire tre excute, mais elle peut se trouver nimporte o dans le chier source. Les programmeurs la place en gnral en tte ou en n du programme pour la localiser facilement. Q Quest-ce quune fonction membre ? R Une fonction membre est utilise en langage C++ et Java. Elle fait partie dune classe (structure spciale employe en C++ et en Java).

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre. Essayez de comprendre les rponses fournies dans lAnnexe G avant de passer au chapitre suivant.

Quiz
1. Utiliserez-vous la programmation structure pour crire vos programmes ? 2. Comment fonctionne la programmation structure ? 3. Les fonctions C sont-elles compatibles avec la programmation structure ? 4. Quelle est la premire ligne de la dnition de fonction et quelles informations contient-elle ?

http://fribok.blogspot.com/

5. Combien de valeurs peut renvoyer une fonction ? 6. Si une fonction ne renvoie pas de valeur, quel type doit-elle avoir dans la dclaration ? 7. Quelle est la diffrence entre la dnition et le prototype dune fonction ? 8. Quest-ce quune variable locale ? 9. Quelle est la particularit des variables locales ? 10. O doit tre place la fonction main()?

Exercices
1. crivez len-tte de la fonction fait le() qui a trois arguments de type char et qui renvoie une valeur de type float au programme appelant. 2. crivez len-tte de la fonction affiche un nombre() qui a un seul argument de type int et qui ne renvoie rien au programme appelant. 3. Quel type de valeur renvoient les fonctions suivantes : a) int affiche erreur(float err nbr);. b) long lit enreg(int rec nbr, int size);. 4. CHERCHEZ LERREUR :

#include <stdio.h> #include <stdlib.h> void print_msg(void); int main() { print_msg("cela est un message afficher"); exit(EXIT_SUCCESS); } void print_msg(void) { puts("cela est un message afficher"); return 0; }

5. CHERCHEZ LERREUR : O est lerreur dans cette dnition de fonction ?



int twice(int y); { return (2 * y); }

6. Transformez le Listing 5.4 pour quil nait besoin que dune instruction return dans la fonction larger of().

http://fribok.blogspot.com/

7. crivez une fonction qui reoit deux nombres en arguments et qui renvoie la valeur correspondant au produit de ces deux nombres. 8. crivez une fonction qui reoit deux nombres en arguments et qui divise le premier par le second si celui-ci est diffrent de zro (utiliser une instruction if). 9. crivez une fonction qui appelle les fonctions des exercices 7 et 8. 10. crivez un programme qui utilise une fonction pour calculer la moyenne de cinq valeurs de type float, donnes par lutilisateur. 11. crivez une fonction rcurrente qui calcule le rsultat de la valeur 3 la puissance du nombre choisi par lutilisateur. Par exemple, si le nombre 4 est tap par lutilisateur, le rsultat sera 81.

http://fribok.blogspot.com/

6
Les instructions de contrle
Le Chapitre 4 vous a donn quelques notions concernant le contrle de lexcution dun programme avec lordre if. Cependant, vous aurez souvent besoin dun contrle plus sophistiqu quun simple test dune condition vraie ou fausse. Ce chapitre vous donne trois nouvelles mthodes pour contrler le ux de vos programmes. Aujourdhui, vous allez apprendre : Utiliser des tableaux simples Utiliser les boucles for, while, et do while pour excuter des instructions plusieurs fois Imbriquer les instructions de contrle dans un programme Le Chapitre 13 compltera les informations de ce chapitre qui sont destines vous fournir des bases au sujet des structures de contrle. Nous esprons ainsi permettre de commencer crire de vrais programmes.

http://fribok.blogspot.com/

Les tableaux
Avant daborder linstruction for, nous allons vous donner quelques notions propos des tableaux, qui seront traits plus en dtail au Chapitre 8. Linstruction for est intimement lie la notion de tableau. En langage C, on ne peut dnir lun sans expliquer lautre. Un tableau est un ensemble demplacements mmoire servant stocker des donnes de mme nom et auxquelles on accde par un index (adresse). Lindex est reprsent entre crochets [] la suite du nom de la variable. Les tableaux devront tre dclars comme toutes les autres variables du langage C. La dclaration spcie le type de donne et la taille du tableau (cest--dire, le nombre dlments quil contient). Voici la dclaration du tableau data de type int, qui contient 1000 lments :
int data[1000]

Les diffrents lments sont indexs de data[0] jusqu data[999]. Le premier lment du tableau est data[0], et non data[1] comme on pourrait naturellement le penser. Chaque lment est lquivalent dune variable entire normale. Lindex peut tre une variable, comme le montre lexemple suivant :
int data[1000]; int compte; compte = 100; data[compte] = 12/* lquivalent de data[100] = 12 */

eils Cons

ne pas faire Dclarer des tableaux et des index trop grands : vous gaspillez la mmoire. Oublier que, en C, lindex des tableaux commence lindice 0, et non 1.

Contrle de lexcution du programme


Par dfaut, lordre dexcution dun programme C se fait de haut en bas (top-down). Lexcution commence avec la premire instruction de la fonction main(), et se poursuit, instruction par instruction, jusqu la dernire. Le langage C contient de nombreuses instructions de contrle qui permettent de modier cet ordre dexcution. Nous avons tudi lordre if, voici trois autres instructions que vous trouverez trs utiles.

http://fribok.blogspot.com/

Linstruction for
Linstruction for permet dexcuter un certain nombre de fois un bloc dune ou plusieurs instructions. On lappelle quelquefois la boucle for, parce que lexcution du programme boucle sur ces instructions plus dune fois. Linstruction for a la structure suivante :
for (initial; condition; incrment) instruction(s)

Initial, condition et incrment sont des expressions ; instruction(s) reprsente une instruction simple ou compose. La boucle for fonctionne de la faon suivante : 1. Lexpression initial est value. Il sagit en gnral dune instruction daffectation qui initialise une valeur particulire. 2. Lexpression condition est value. condition est souvent une expression de comparaison. 3. Si condition est fausse (valeur 0), linstruction for se termine et lexcution reprend la premire instruction qui suit instruction(s). 4. Si condition est vraie(valeur diffrente de 0), les instructions de instruction(s) sont excutes. 5. Lexpression incrment est calcule et lexcution reprend ltape 2.
Figure 6.1 Diagramme de fonctionnement de linstruction for.

Dbut

valuation de initial

valuation de increment

for (initial; condition; increment) Instruction(s) valuation de la condition VRAI


Excution des instruction(s)

FAUX Fin

http://fribok.blogspot.com/

Le Listing 6.1 prsente un exemple simple de programme utilisant une boucle for. Ce programme afche les nombres de 1 20. Le code est, bien sr, beaucoup plus concis que si vous aviez utilis une instruction printf() pour chaque valeur. Listing 6.1 : Linstruction for
1: /* Exemple simple dutilisation dune instruction for */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int count; 6: 7: int main() 8: { 9:/* Affichage des nombres de 1 20 */ 10: 11:for (count = 1; count <= 20; count++) 12:printf("%d\n", count); 13:exit(EXIT_SUCCESS); 14: } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Analyse La ligne 3 de ce programme appelle le traditionnel chier dentres/sorties. La ligne 5 dclare une variable count de type int qui sera utilise dans la boucle. Les lignes 11 et 12 constituent la boucle for. Quand lexcution atteint linstruction for, linstruction initiale count =1 est excute : la variable count est initialise pour la suite. La

http://fribok.blogspot.com/

deuxime tape est lvaluation de la condition count <=20. count tant gale 1, la condition est vraie, linstruction printf() est donc excute. Ltape suivante est le calcul de lincrmentation count++ qui ajoute 1 la valeur de count. Le programme recommence alors la boucle et contrle la condition de nouveau. Si elle est vraie, printf() sera excute de nouveau, la variable count sera incrmente et la condition value. Le programme va boucler sur ces instructions jusqu ce que la condition devienne fausse. Il sortira alors de la boucle pour continuer lexcution ligne 13 (qui renvoie 0).
Figure 6.2 Voici comment opre la boucle for du Listing 6.1.

Dbut

On attribue la valeur 1 count

On incrmente count de 1

for (count = 1; count < = 20; count++) print ( "\n%d", count); Count OUI Excution de printf()

< = 20?

NON Fin

Linstruction for est souvent utilise, comme dans lexemple prcdent, pour "compter" en incrmentant un compteur jusqu une valeur donne. Vous pouvez bien entendu dcrmenter un compteur de la mme faon.
for (count = 100; count > 0; count )

Le compteur peut tre incrment dune valeur diffrente de 1 :


for (count = 0; count < 1000; count +=5)

Linstruction for nest pas contraignante. Vous pouvez omettre lexpression dinitialisation du "compteur" si la variable a t initialise auparavant. Vous devez tout de mme conserver le point-virgule :
count = 1; for (; count < 1000; count++)

http://fribok.blogspot.com/

Cette expression dinitialisation peut tre nimporte quelle expression C. Elle nest excute quune fois au dbut de lexcution de la boucle for. Voici un exemple :
count = 1; for (printf("Nous allons trier le tableau"); count < 1000; count++) /* instructions de tri */

Vous pouvez aussi omettre lexpression dincrmentation et mettre le compteur jour dans les instructions de la boucle for. Voici un exemple de boucle qui afche les nombres de 0 99 :
for (count = 0; count < 100;) printf("%d", count++);

Lexpression de test qui termine la boucle peut tre nimporte quelle expression C. Tant que cette expression est vraie (diffrente de 0), linstruction for continue sexcuter. Vous pouvez utiliser les oprateurs logiques pour construire des expressions de test complexes. Par exemple, linstruction for suivante afche les lments dun tableau appel tableau[], jusqu ce quelle rencontre la valeur 0 ou la n du tableau :
for (count = 0; count < 1000 && tableau[count]!= 0; count++) printf("%d", tableau[count]);

Cette boucle for peut tre simplie de la faon suivante :


for (count = 0; count < 1000 && tableau[count];) printf("%d", tableau[count++]);

Une boucle for peut avoir une instruction nulle, tout le travail tant fait dans linstruction for. Lexemple suivant initialise les 1000 lments dun tableau la valeur 50 :
for (count = 0; count < 1000; tableau[count++]=50) ;

Au Chapitre 4, nous avions annonc que loprateur virgule tait souvent utilis dans les boucles for. En effet, vous pouvez crer une expression en sparant deux sous-expressions par une virgule. Les deux sous-expressions sont values de gauche droite, et lexpression prend la valeur de la sous-expression de droite. En utilisant la virgule, vous pouvez faire excuter plusieurs fonctions par une seule instruction for. Supposons que nous ayons deux tableaux de 1000 lments a[] et b[]. On veut copier le contenu de a[] dans b[] dans un ordre inverse de telle sorte que b[0]=a[999], b[1]=a[998], etc.. Voici linstruction for correspondante :
for (i = 0, j = 999; i < 1000; i++, j) b[j] = a[i];

http://fribok.blogspot.com/

La virgule a permis dinitialiser les deux variables i et j, puis de les incrmenter chaque boucle.

Syntaxe de la commande for


for (initial; condition; incrment) instruction(s)

initial est une expression du langage C, gnralement une instruction daffectation qui initialise une variable. condition est une expression C, habituellement une comparaison. Quand condition est fausse (valeur 0), linstruction for se termine et lexcution se poursuit avec la premire instruction qui suit instruction(s). Dans le cas contraire, les instructions de instruc tion(s) sont excutes. incrment est une expression C qui, en rgle gnrale, incrmente la valeur de la variable initialise dans lexpression initial. instruction(s) reprsente les instructions excutes aussi longtemps que la condition reste vraie. Linstruction for est une instruction qui boucle. Lexpression initial est excute la premire, suivie de la condition. Si celle-ci est vraie, les instructions sont excutes et lexpression incrment est calcule. La condition est alors contrle de nouveau et lexcution se poursuit jusqu ce que la condition devienne fausse. Exemple 1
/* Affiche la valeur de x en comptant de 0 9 */ int x; for (x=0; x<10; x++) printf("\nLa valeur de x est%d", x);

Exemple 2
/* Demande une valeur lutilisateur jusqu lobtention de 99 */ int nbr = 0; for (; nbr!= 99;) scanf("%d", &nbr);

Exemple 3
/* Permet lutilisateur dentrer 10 valeurs entires. */ /* Les valeurs sont stockes dans un tableau appel valeur. */ /* La boucle est interrompue si lutilisateur tape 99. */

http://fribok.blogspot.com/

int valeur[10]; int ctr, nbr=0; for (ctr = 0; ctr < 10 && nbr!= 99; ctr++) { puts("Entrez un nombre ou 99 pour sortir"); scanf("%d", &nbr); valeur[ctr] = nbr; }

Instructions for imbriques


On peut excuter une instruction for lintrieur dune autre instruction for. En imbriquant des instructions for, on peut raliser une programmation trs complexe. Listing 6.2 : Instructions for imbriques
1: /* Exemple de deux instructions for imbriques */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: void boite(int ligne, int colonne); 6: 7: int main() 8: { 9:boite(8, 35); 10:exit(EXIT_SUCCESS); 11: } 12: 13: void boite(int ligne, int colonne) 14: { 15:int col; 16:for(; ligne> 0; ligne) 17:{ 18: for(col = colonne; col > 0; col) 19: printf("X"); 20: 21: printf("\n"); 22:} 23: } XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

http://fribok.blogspot.com/

Analyse Le travail le plus important de ce programme est ralis la ligne 18. Quand vous lexcutez, 280 "X" safchent, formant un tableau de 8 lignes et 35 colonnes. Le programme ne contient quune seule commande dafchage du caractre "X", mais elle se trouve lintrieur de deux boucles imbriques. La ligne 5 de ce programme source contient le prototype de la fonction bote(). Cette fonction utilise deux variables de type int, ligneet colonne, qui reprsentent les dimensions du tableau de "X". La fonction principale main() appelle la fonction bote() en ligne 9 et lui transmet la valeur 8 pour les lignes et 35 pour les colonnes. tudions la fonction bote(). Deux choses vous paraissent certainement tranges : pour quelle raison a-t-on dclar une variable locale col, et pourquoi a-t-on utilis une seconde fois la fonction printf() en ligne 21 ? Ces deux points vont tre claircis par ltude des deux boucles for. La premire commence en ligne 16. Elle ne contient pas de partie dinitialisation, car la valeur initiale de lignea t transmise la fonction. La partie condition indique que cette boucle sexcutera jusqu ce que lignesoit gale 0. la premire excution de cette boucle, ligneest gale 8. Lexcution du programme se poursuit en ligne 18. La ligne 18 contient la seconde boucle for. Le paramtre transmis est colonne, que lon copie dans la variable col de type int. La valeur initiale de col est donc 35 et colonne va conserver cette valeur inchange. La variable col est suprieure 0, la ligne 19 est donc excute : on afche un "X" sur lcran. La valeur de col est diminue de 1 et la boucle continue. Quand col atteint la valeur 0, la boucle se termine et la ligne 21 prend le contrle. Cette ligne envoie vers lcran un retour la ligne. Cest maintenant la dernire tape de la premire boucle : La partie incrment sexcute en diminuant la valeur de lignede 1, ce qui lui donne la valeur 7. Le contrle est donn de nouveau la ligne 18. Remarquez bien que la dernire valeur de col tait 0 ; si on avait utilis la variable colonne le test de condition serait dj faux et on naurait imprim quune seule ligne.
eils Cons

faire Ne pas oublier le point-virgule dans une boucle for, avec une instruction nulle. Pour plus de clart, mettez-le sur une ligne spare, ou la n de linstruction for en lisolant par un espace :

for (count = 0; count < 1000; tableau[count] = 50);

ne pas faire crire une instruction for trop charge. Bien que lon puisse utiliser des virgules, il est souvent plus simple de mettre certaines fonctionnalits dans le corps de la boucle.

http://fribok.blogspot.com/

Linstruction while
Linstruction while, que lon peut appeler la boucle while, excute un bloc dinstructions tant quune condition reste vraie.
while (condition) instruction(s)

La condition est une expression C et instruction(s) reprsente une instruction simple ou compose. La boucle while fonctionne de la faon suivante : 1. La condition est value. 2. Si condition est fausse (valeur 0), linstruction while se termine et lexcution se poursuit avec linstruction qui suit immdiatement instruction(s). 3. Si condition est vraie (valeur diffrente de 0), les instructions de instruction(s) sont excutes. 4. Lexcution reprend ltape 1.
Figure 6.3 Diagramme de fonctionnement dune instruction while.
while (condition) instructions; valuation de la condition VRAI Excution des instructions

Dbut

FAUX Fin

Le Listing 6.3 dcrit un programme simple utilisant une instruction while pour imprimer des nombres de 1 20. Listing 6.3 : Linstruction while
1: 2: 3: 4: 5: 6: /* Exemple dexcution dune instruction while simple */ #include <stdio.h> #include <stdlib.h> int count;

http://fribok.blogspot.com/

7: int main() 8: { 9:/* Affiche les nombres de 1 20 */ 10: 11:count = 1; 12: 13:while (count <= 20) 14:{ 15: printf("%d\n", count); 16: count++; 17:} 18:exit(EXIT_SUCCESS); 19: } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Analyse Comparez le Listing 6.3 avec le Listing 6.1 qui excutait la mme tche avec une instruction for. En ligne 11, la variable count est initialise 1. Linstruction while ne contient pas de partie dinitialisation, qui doit donc tre faite avant. Linstruction while se trouve en ligne 13 et contient la mme condition que la boucle for du Listing 6.1 : count <=20. Dans la boucle while, cest la ligne 16 qui est charge dincrmenter la variable count. Si vous aviez oubli de coder cette ligne, le programme naurait pas su quand sarrter, car count aurait conserv la valeur 1 qui est toujours infrieure 20. Une instruction while est une instruction for sans les deux parties initialisation et incrment.
for (; condition;)

http://fribok.blogspot.com/

est donc lquivalent de :


while (condition)

Tout ce que vous pouvez faire avec for peut tre fait avec while. Si vous utilisez linstruction while, vous devez initialiser vos variables avant, et le "compteur" doit tre mis jour dans la partie instruction(s). Quand les parties initialisation et incrment sont ncessaires, les programmeurs expriments prfrent utiliser linstruction for. Les trois parties initialisation, condition, et incrment tant runies sur la mme ligne, le code est plus facile lire et modier.

Syntaxe de la commande while


while (condition) instruction(s)

condition est une expression du langage C. En gnral, cest une expression de comparaison. Quand cette condition est fausse (valeur 0), linstruction while se termine et lexcution se poursuit avec linstruction qui suit instruction(s). Sinon, les instruc tion(s) sont excutes. instruction(s) reprsente des instructions qui sont excutes tant que condition reste vraie. while est une instruction C qui boucle. Elle permet de rpter lexcution dune instruction, ou dun bloc dinstructions, tant quune condition reste vraie (valeur diffrente de 0). Si la condition est fausse la premire excution de linstruction while, les instruc tion(s) ne sont jamais excutes. Exemple 1
int x = 0; while (x < 10) { printf("La valeur de x est%d\n", x); x++; }

Exemple 2
/* saisie des nombres entrs par lutilisateur et sortie si suprieur 99 */ int nbr = 0; while (nbr <= 99) scanf("%d", &nbr);

http://fribok.blogspot.com/

Exemple 3
/* Lutilisateur peut entrer jusqu 10 valeurs entires */ /* Ces valeurs sont stockes dans un tableau appel valeur */ /* la boucle se termine si lutilisateur rentre 99 */ int valeur[10]; int ctr = 0; int nbr; while (ctr < 10 && nbr!= 99) { puts("Entrez un nombre ou 99 pour sortir ); scanf("%d", &nbr); valeur[ctr] = nbr; ctr++; }

Instructions while imbriques


On peut imbriquer des instructions while comme avec for ou if. Le Listing 6.4 vous en montre un exemple qui ne reprsente pas le meilleur usage de while, mais qui vous propose quelques ides nouvelles. Listing 6.4 : Instructions while imbriques
1: /* Exemple dinstructions while imbriques */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int tableau[5]; 6: 7: int main() 8: { 9:int ctr = 0, 10:nbr = 0; 11: 12:printf("Ce programme vous demande dentrer 5 nombres,\n"); 13:printf("chacun compris entre 1 et 10\n"); 14: 15:while (ctr < 5) 16:{ 17: nbr = 0; 18:while (nbr < 1 || nbr > 10) 19: { 20: printf("\nEntrez le nombre numro%d sur 5: ", ctr+1); 21: scanf("%d", &nbr); 22:}

http://fribok.blogspot.com/

Listing 6.4 : Instructions while imbriques (suite)


23: 24: tableau[ctr] = nbr; 25: ctr++; 26:} 27: 28:for(ctr = 0; ctr < 5; ctr++) 29:printf("La valeur%d est%d\n", ctr+1, tableau[ctr]); 30:exit(EXIT_SUCCESS); 31: } Ce programme vous demande dentrer 5 nombres chacun compris entre 1 et 10 Entrez le nombre numro 1 sur 5: 3 Entrez le nombre numro 2 sur 5: 6 Entrez le nombre numro 3 sur 5: 3 Entrez le nombre numro 4 sur 5: 9 Entrez le nombre numro 5 sur 5: 2 La La La La La valeur valeur valeur valeur valeur 1 2 3 4 5 est est est est est 3 6 3 9 2

Analyse Vous retrouvez en ligne 1 le commentaire de description du programme ; la ligne 3 appelle le traditionnel chier den-tte. La ligne 5 dclare le tableau dans lequel on pourra stocker cinq valeurs entires. La fonction main() contient deux variables locales, ctr et nbr, qui sont dclares et initialises en lignes 9 et 10. Remarquez lutilisation de la virgule qui est une pratique courante des programmeurs. Cela permet de dclarer une variable par ligne, sans avoir rpter int. Les lignes 12 et 13 afchent pour lutilisateur ce que le programme lui demande de faire. La premire boucle while, lignes 15 26, contient une boucle while imbrique en lignes 18 22. Elle va sexcuter tant que la variable ctr sera infrieure 5. Cette premire boucle initialise nbr 0 la ligne 17, puis la boucle imbrique rcupre le nombre entr par lutilisateur pour la variable nbr. La ligne 24 stocke ce nombre dans le tableau et la valeur de ctr est incrmente en ligne 25. Ensuite, la boucle principale recommence. La boucle intrieure est un bon exemple dutilisation de while. Les nombres valides sont les nombres de 1 10 ; tant que lutilisateur choisit un nombre dans cet intervalle, lexcution na pas de raison de sinterrompre. Ce sont les lignes 18 22 qui contrlent le nombre

http://fribok.blogspot.com/

entr par lutilisateur : linstruction while va envoyer le mme message lutilisateur tant que ce nombre, nbr, sera infrieur 1 ou suprieur 10. Enn, les lignes 28 et 29 impriment tous les nombres qui ont t stocks dans le tableau.
eils Cons

faire Utilisez linstruction for plutt que while si vous avez besoin dinitialiser et dincrmenter dans la boucle. Linstruction for runit linitialisation, la condition, et lincrmentation sur la mme ligne. ne pas faire Coder des instructions du genre while (x) lorsque ce nest pas ncessaire. crivez plutt while (x!= 0); les deux instructions sont correctes, mais la seconde sera plus facile corriger en cas de problme.

La boucle do-while
La troisime boucle est la boucle do while qui excute un bloc dinstructions tant quune condition reste vraie. La diffrence entre la boucle do while et les deux boucles prcdentes est que le test de la condition seffectue la n de la boucle. Pour les deux autres, le test se fait au dbut. Linstruction do while a la structure suivante :
do instructions while (condition);

condition est une expression du langage C, et instruction(s) reprsente une instruction simple ou compose. Quand une instruction do while est rencontre pendant lexcution du programme, voici ce qui se passe : 1. Les instructions de instruction(s) sont excutes. 2. condition est teste. Si elle est vraie, lexcution reprend ltape 1. Si elle est fausse, la boucle se termine. Le test de condition tant ralis la n, les instructions qui font partie de la boucle do while sont toujours excutes au moins une fois. Au contraire, dans les boucles for et do while, si le test est faux ds le dbut, les instructions ne sont jamais excutes. La boucle do while est moins souvent utilise que for ou while. Son intrt rside surtout dans le fait que les instructions sont excutes au moins une fois.

http://fribok.blogspot.com/

Figure 6.4 Diagramme de fonctionnement de la boucle do-while.

Dbut

Excution des instructions do instruction(s); while (condition); VRAI

valuation de la condition

FAUX Fin

Listing 6.5 : La boucle do while


1: /* Exemple simple dutilisation de linstruction do-while */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int choix_menu(void); 6: 7: int main() 8: { 9:int choix; 10: 11:choix = choix_menu(); 12: 13:printf("Vous avez choisi loption%d\n du menu", choix); 14:exit(EXIT_SUCCESS); 15: } 16: 17: int choix_menu(void) 18: { 19:int selection = 0; 20: 21:do 22:{ 23:printf("\n"); 24:printf("1 - Ajouter un enregistrement\n"); 25:printf("2 - Changer un enregistrement\n"); 26:printf("3 - Effacer un enregistrement\n"); 27:printf("4 - Sortie\n"); 28:printf("\n"); 29:printf("Entrez votre choix:");

http://fribok.blogspot.com/

30: 31:scanf("%d", &selection); 32: 33:}while (selection < 1 || selection > 4); 34: 35:return selection; 36: } 1 2 3 4 Ajouter un enregistrement Changer un enregistrement Effacer un enregistrement Sortir

Entrez votre choix: 8 1 2 3 4 Ajouter un enregistrement Changer un enregistrement Effacer un enregistrement Sortir

Entrez votre choix: 4 Vous avez choisi loption 4 du menu

Analyse Ce programme propose un menu comprenant quatre options. Lutilisateur en choisit une et le programme lui afche le numro slectionn. Ce concept sera largement repris par la suite avec des programmes plus complexes. La fonction principale main() (lignes 7 14) ne comporte aucune nouveaut. La fonction main() aurait pu tre crite sur une seule ligne : printf("Vous avez choisi loption %d du menu", choix_menu()); Si vous aviez besoin de prolonger ce programme en associant une tche chaque slection, vous auriez besoin de la valeur renvoye par choix menu. Il est donc prfrable de laffecter une variable (choix).

Info

Le code de la fonction choix menu se trouve aux lignes 17 36. Cette fonction permet dafcher le menu lcran (lignes 23 29) et de rcuprer le numro choisi par lutilisateur. La boucle do while a t choisie, car le menu doit tre afch au moins une fois pour connatre la dcision de lutilisateur. Dans ce cas, le menu safche jusqu ce quun numro valide soit entr au clavier. La ligne 33 contient la partie while de la boucle et contrle la valeur slectionne (slection). Si cette valeur nest pas un nombre entier compris entre 1 et 4, le menu rapparat et un message demande lutilisateur deffectuer un autre choix. Si la valeur est correcte, lexcution se poursuit ligne 35 avec le stockage de cette valeur dans la variable selection.

http://fribok.blogspot.com/

Syntaxe de la commande do-while


do { instruction(s) }while (condition);

condition est une expression du langage C, en rgle gnrale une comparaison. Quand la condition est fausse (zro), linstruction while se termine et lexcution se poursuit avec linstruction qui suit celle de while. Sinon le programme reprend au niveau du do et les instructions de instruction(s) sont excutes. instruction(s) reprsente une ou plusieurs instructions excutes une premire fois au dmarrage de la boucle, puis tant que la condition reste vraie. Une instruction do while est une instruction C qui boucle. Elle permet dexcuter une instruction ou un bloc dinstructions aussi longtemps quune condition reste vraie. Contrairement while, la boucle do while sexcute au moins une fois. Exemple 1
/* Le message est affich mme si la condition est fausse! */ int x = 10; do { printf("La valeur de x est%d\n", x); }while (x!= 10);

Exemple 2
/* Lit des nombres jusqu ce que le nombre entr soit suprieur 99 */ int nbr; do { scanf("%d", &nbr); }while (nbr <= 99);

Exemple 3
/* Permet lutilisateur dentrer dix valeurs entires */ /* Ces valeurs sont stockes dans un tableau appel valeur */ /* On sort de la boucle si lutilisateur entre 99 */ int valeur[10]; int ctr = 0; int nbr; do { puts("Entrez un nombre, ou 99 pour sortir"); scanf("%d", &nbr); ctr++; }while (ctr < 10 && nbr!= 99);

http://fribok.blogspot.com/

Les boucles imbriques


Le terme boucle imbrique fait rfrence une boucle situe lintrieur dune autre boucle. Le langage C nest pas contraignant sur lutilisation de telles boucles. La seule contrainte est que la boucle intrieure doit tre entirement contenue dans la boucle extrieure. Voici un exemple de boucle qui "dborde" ne pas suivre :
for (count = 1; count < 100; count++) { do { /* la boucle do-while */ } /* fin de la boucle for */ } while (x!= 0);

Voici le mme exemple corrig :


for (count = 1; count < 100; count++) { do { /* la boucle do-while */ } while (x!= 0); } /* fin de la boucle for */

Rappelez-vous, lorsque vous utiliserez des boucles imbriques, que des changements raliss dans la boucle intrieure peuvent affecter la boucle extrieure. Les variables de la boucle intrieure peuvent cependant tre indpendantes. Dans notre exemple ce nest pas le cas, mais dans lexemple prcdent, la boucle intrieure agissant sur la valeur de count, modiait le nombre dexcutions de la boucle for. Prenez lhabitude de dcaler dune tabulation chaque niveau de boucle pour les diffrencier facilement. faire Inclure entirement une boucle imbrique dans la boucle extrieure. Il ne doit pas y avoir de recouvrement. Utiliser la boucle do while quand il faut excuter les instructions au moins une fois.

eils Cons

http://fribok.blogspot.com/

Rsum
Vous avez maintenant le matriel ncessaire pour commencer coder vos programmes. Le langage C possde trois instructions de boucle pour contrler lexcution des programmes : for, while, et do while. Chacune de ces instructions permet dexcuter zro, une ou plusieurs fois une instruction ou un bloc dinstructions, en fonction du test dune condition. En programmation, de nombreuses tches peuvent tre ralises avec des boucles. Dans le principe, ces trois boucles peuvent raliser les mmes tches, mais elles sont diffrentes. Linstruction for permet, en une seule ligne de code, dinitialiser, dvaluer, et dincrmenter. Linstruction while s excute tant que la condition reste vraie. Enn, linstruction do while sexcute une fois, puis de nouveau jusqu ce que la condition soit fausse. Le terme de boucle imbrique dsigne une boucle compltement incluse dans une autre boucle. Le langage C permet dimbriquer toutes ses commandes. Nous avons vu comment imbriquer des ordres if dans le Chapitre 4.

Q&R
Q Comment choisir entre for, while, et do while? R Si vous tudiez la syntaxe de ces trois boucles, vous remarquez quelles servent toutes rsoudre un problme de boucle tout en ayant chacune une particularit. Si votre boucle a besoin de linitialisation et de lincrmentation dune variable, linstruction for sera plus approprie. Si la condition est importante et que le nombre dexcutions de la boucle importe peu, alors le choix de while est judicieux. Si les instructions ont besoin dtre excutes au moins une fois, do while sera le meilleur choix. Q Combien de niveaux de boucles puis-je imbriquer ? R Vous pouvez imbriquer autant de niveaux de boucles que vous le voulez. Toutefois, si vous avez besoin dimbriquer plus de deux niveaux de boucles dans votre programme, essayez dutiliser une fonction. Cela diminuera le nombre daccolades ncessaires, et une fonction sera peut-tre plus facile coder et corriger. Q Puis-je imbriquer des instructions de boucle diffrentes ? R Vous pouvez imbriquer une boucle if, for, while, do while dans nimporte quelle autre commande. Vous en aurez souvent besoin au cours de vos programmations.

http://fribok.blogspot.com/

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre. Essayez de comprendre les rponses fournies dans lAnnexe G avant de passer au chapitre suivant.

Quiz
1. Quelle est la valeur dindex du premier lment dun tableau ? 2. Quelle est la diffrence entre une instruction for et une instruction while? 3. Quelle est la diffrence entre une instruction while et une instruction do while? 4. Une instruction while peut-elle donner le mme rsultat quune instruction for? 5. De quoi faut-il se rappeler propos des instructions imbriques ? 6. Peut-on imbriquer une instruction while dans une instruction do while? 7. Quelles sont les quatre parties dune instruction for? 8. Quelles sont les deux parties dune instruction while? 9. Quelles sont les deux parties dune instruction dowhile?

Exercices
1. crivez la dclaration correspondant un tableau qui contiendra 50 valeurs de type long. 2. crivez linstruction qui attribue la valeur 123,456 au cinquantime lment du tableau de lexercice 1. 3. Quelle est la valeur de x aprs lexcution de linstruction suivante ?
for (x = 0; x < 100, x++);

4. Quelle est la valeur de ctr aprs lexcution de linstruction suivante ?


for (ctr = 0; ctr < 10; +=3);

5. Combien de caractres X la boucle for suivante afche-t-elle ?


for (x = 0; x < 10; x++) for (y = 5; y > 0; y) puts("X");

6. crivez une instruction for pour compter de 1 100 de 3 en 3.

http://fribok.blogspot.com/

7. crivez une instruction while pour compter de 1 100 de 3 en 3. 8. crivez une instruction do while pour compter de 1 100 de 3 en 3. 9. CHERCHEZ LERREUR :
record = 0; while (record < 100) { printf("Enregistrement%d\n", record); printf("Prochain nombre ...\n"); }

10. CHERCHEZ LERREUR (Ce nest pas MAXVALUES !)


for (counter = 1; counter < MAXVALUES; counter++); printf("Counter =%d\n", counter);

http://fribok.blogspot.com/

7
Les principes de base des entres/sorties
La plupart des programmes que vous allez crire auront besoin dafcher des informations lcran, ou de lire des donnes entres au clavier. Aujourdhui, vous allez apprendre :

Afcher des informations lcran avec les fonctions de bibliothque printf() et puts() Mettre en forme les messages envoys vers lcran Lire les donnes entres au clavier avec la fonction de bibliothque scanf()

http://fribok.blogspot.com/

Afcher des informations lcran


Les deux fonctions de bibliothque les plus souvent utilises pour afcher des informations lcran sont printf() et puts().

La fonction printf()
Nous avons vu de nombreux exemples dutilisation de printf(), mais vous nen connaissez pas encore le mode de fonctionnement. La fonction printf(), qui fait partie de la bibliothque standard du C, est la plus polyvalente pour afcher des informations lcran. Afcher un texte sur lcran est trs simple : il suft dappeler la fonction printf() et de lui passer le message entre guillemets(" "). Linstruction suivante afche le message une erreur sest produite!
printf("une erreur sest produite!");

Pour introduire la valeur dune variable dans votre message, cest un peu plus compliqu. Supposons, par exemple, que vous vouliez afcher la valeur de la variable x avec un texte descriptif, et commencer le message sur une nouvelle ligne. Il faudra utiliser linstruction suivante :
printf("La valeur de x est%d\n", x);

Si la valeur de x est 12, le rsultat lcran de linstruction prcdente sera :


La valeur de x est 12

Dans notre exemple, nous avons transmis deux arguments printf(). Le premier est la chane format qui se trouve entre guillemets, le second, le nom de la variable qui contient la valeur afcher.

Les chanes format de print()


Comme son nom lindique, la chane format de printf() indique les spcications de format pour la chane mettre. Voici les trois lments que lon peut introduire dans une chane format :

Un texte simple qui sera afch tel quel. "La valeur de x est" reprsente la partie texte de lexemple prcdent. Un ordre de contrle qui commence par un antislash (\) suivi dun caractre. Dans notre exemple, \n est lordre de contrle. Cest le caractre de retour la ligne ; il signie littralement "se placer au dbut de la prochaine ligne".

http://fribok.blogspot.com/

Une spcication de conversion qui est reprsente par le signe de pourcentage (%) suivi dun caractre. Celle de notre exemple est %d. Elle indique la fonction printf() comment interprter les variables que lon veut afcher. %d signie pour printf() que la variable x est un entier dcimal sign.

Tableau 7.1 : Ordres de contrle le plus souvent utiliss

Ordre \a \b \n \t \\

Signication
Sonnerie Retour arrire Retour la ligne Tabulation horizontale Backslash (antislash \)

Les ordres de contrle de la chane format permettent de contrler lemplacement nal du message en dplaant le curseur. Ils permettent aussi dafcher des caractres qui ont ordinairement une signication particulire pour printf(). Pour imprimer le caractre (\) par exemple, il faut en introduire deux (\\) dans la chane format. Le premier indique printf() que le second devra tre interprt comme un simple caractre, et non comme le dbut dun ordre de contrle. En rgle gnrale, le caractre (\) demande printf() dinterprter le caractre qui suit dune faon particulire. En voici quelques exemples :
Ordre n \n \" " Signication
Le caractre n Retour la ligne Le guillemet Dbut ou n dune chane

Le Tableau 7.1 contient les ordres de contrle les plus utiliss. Vous en trouverez la liste complte dans le Chapitre 15. Listing 7.1 : Utilisation des ordres de contrle avec printf()
1: /* Ce programme contient des ordres de contrle 2:souvent utiliss */ 3: #include <stdio.h> 4: #include <stdlib.h> 5: #define QUIT3 6:

http://fribok.blogspot.com/

Listing 7.1 : Utilisation des ordres de contrle avec printf() (suite)


7: intchoix_menu(void); 8: void affiche(void); 9: 10: int main() 11: { 12:int choix = 0; 13: 14:while(choix!= QUIT) 15:{ 16:choix = choix_menu(); 17: 18:if(choix == 1) 19:printf("\nLordinateur va biper\a\a\a"); 20:else 21:{ 22:if(choix == 2) 23:affiche(); 24:} 25:} 26:printf("Vous avez choisi de sortir!\n"); 27:exit(EXIT_FAILURE); 28: } 29: 30: int choix_menu(void) 31: { 32:int selection = 0; 33: 34:do 35:{ 36:printf("\n"); 37:printf("\n1 - Bip ordinateur"); 38:printf("\n2 - Affichage "); 39:printf("\n3 - Sortir"); 40:printf("\n"); 41:printf("\nEntrez votre choix:"); 42: 43:scanf("%d", &selection); 44: 45:}while (selection < 1 || selection > 3); 46: 47:return selection; 48: } 49: 50: void affiche(void) 51: { 52:printf("\nExemple daffichage"); 53:printf("\n\nOrdre\tSignification"); 54:printf("\n======\t=============="); 55:printf("\n\\a\t\tsonnerie "); 56:printf("\n\\b\t\tretour arrire"); 57:printf("\n...\t\t..."); 58: } 1 - Bip ordinateur 2 - Affichage 3 - Sortir

http://fribok.blogspot.com/

Entrez votre choix: 1 Lordinateur va biper 1 - Bip ordinateur 2 - Affichage 3 - Sortir Entrez votre choix: 2 Exemple daffichage OrdreSignification =================== \asonnerie \bRetour arrire 1 - Bip ordinateur 2 - Affichage 3 - Sortir Entrez votre choix: 3 Vous avez choisi de sortir!

Analyse Le chier en-tte stdio.h est inclus ligne 2 pour pouvoir utiliser la fonction printf(). La ligne 5 dnit la constante QUIT et les lignes 7 et 8 le prototype des deux fonctions : affi che() et choix menu(). La dnition de choix menu se trouve aux lignes 30 48. Cette fonction est analogue la fonction menu du Listing 6.5. Les lignes 36 41 contiennent les appels de la fonction printf() avec les ordres de retour la ligne. La ligne 36 pourrait tre supprime en transformant la ligne 37 de cette faon :
printf("\n\n1 - Bip ordinateur");

Examinons la fonction main(). Une boucle while commence en ligne 14 et sexcute tant que lutilisateur ne choisit pas de sortir (choix diffrent de QUIT). QUIT tant une constante, elle aurait pu tre remplace par la valeur 3. Quoi quil en soit, le programme y a gagn en clart. La ligne 16 lit la variable choix qui est analyse par linstruction if aux lignes 18 24. Si le choix de lutilisateur est 1, la ligne 19 provoque un retour la ligne, afche le message et fait biper trois fois lordinateur. Si le choix est 2, la ligne 23 appelle la fonction affiche(). La dnition de la fonction affiche() se trouve aux lignes 50 58. Cette fonction facilite lafchage lcran dun texte mis en forme avec des retours la ligne. Les lignes 53 57 utilisent lordre de contrle \t (tabulation) pour aligner les colonnes du tableau. Pour comprendre les lignes 55 et 56, il faut analyser la chane de gauche droite. La ligne 55 provoque un retour la ligne (\n), afche un antislash (\) suivi du caractre a, puis

http://fribok.blogspot.com/

dplace le curseur de deux tabulations (\t \t) et, enn, afche le texte sonnerie. La ligne 56 suit le mme format. Ce programme afche les deux premires lignes du Tableau 7.1. Dans lexercice 9 de ce chapitre, vous devrez complter ce programme pour afcher le tableau entier.

Les spcications de conversion de printf()


La chane format contient des spcications de conversion qui doivent correspondre, en nombre et en type, aux arguments. Cela signie que si vous voulez afcher une variable de type entier dcimal sign (types int et long), vous devez inclure dans la chane %d. Pour un entier dcimal non sign (types unsigned int et unsigned long), vous devez inclure %u. Enn, pour une variable virgule ottante (types float ou double), il faut utiliser %f.
Tableau 7.2 : Spcications de conversion les plus frquentes

Conversion %c %d %ld %f %s %u %lu

Signication
Un seul caractre Entier dcimal sign Entier dcimal sign long Nombre virgule ottante Chane de caractres Entier dcimal non sign Entier dcimal non sign long

Types convertis char int, short, long float, double tableaux char unsigned int, unsigned short unsigned long

Le texte contenu dans une chane format, cest--dire tout ce qui nest pas ordre de contrle ou spcication de conversion, est afch de faon littrale en incluant tous les espaces. Linstruction printf() nest pas limite quant au nombre de variables quelle peut afcher. La chane format doit cependant contenir une spcication de conversion pour chacune de ces variables. La correspondance conversion-variable se fait de gauche droite. Par exemple, si vous crivez :
printf("taux =%f, montant =%d", taux, montant);

la spcication de conversion %f sera remplace par la variable taux, et %d sera remplace par la variable montant. Si la chane contient plus de variables que de spcications de

http://fribok.blogspot.com/

conversion, les variables supplmentaires napparaissent pas. Sil y a plus de spcications de conversion que de variables, la fonction printf() afche nimporte quoi. Il ny a pas de restriction sur ce que vous pouvez afcher avec la fonction printf(). Un argument peut tre une expression du langage C. Pour afcher la somme de x et y, vous pouvez crire, par exemple :
z = x+y; printf("%d", z);

ou
printf("%d", x+y);

Un programme qui utilise une fonction printf() doit obligatoirement contenir le chier en-tte stdio.h. Listing 7.2 : Utilisation de la fonction printf() pour afcher des valeurs numriques
1: /* Utilisation de printf() pour afficher des valeurs numriques.*/ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int a = 2, b = 10, c = 50; 6: float f = 1.05, g = 25.5, h = 0.1; 7: 8: int main() 9: { 10: printf("\nValeurs dcimales sans tabulation:%d%d%d", a, b, c); 11: printf("\nValeurs dcimales avec tabulations: \t%d \t%d \t%d", 12:a, b, c); 13: printf("\nTrois types float sur 1 ligne: \t%f\t%f\t%f", f, g, h); 14: printf("\nTrois types float sur 3 lignes: \n\t%f\n\t%f\n\t%f", f, 15:g, h); 16: printf("\nLe taux est de%f%%", f); 17: printf("\nLe rsultat de%f/%f est%f\n", g, f, g / f); 18: exit(EXIT_FAILURE); 19: } Valeurs dcimales sans tabulation: 21050 Valeurs dcimales avec tabulations:21050 Trois types float sur une ligne:1.05000025.5000000.100000 Trois types float sur trois lignes: 1.050000 25.500000 0.100000 Le taux est de 1.050000% Le rsultat de 25.500000/1.050000 est 24.285715

http://fribok.blogspot.com/

Analyse Les lignes 10 et 11 de ce programme afchent les trois dcimales a, b, et c. La ligne 11 le fait en ajoutant des tabulations, absentes la ligne 10. La ligne 13 du programme afche les trois variables virgule ottante f, g et h sur une ligne, la ligne 14 le fait sur trois lignes. La ligne 16 afche la variable virgule ottante f suivie du signe %. La ligne 17 illustre un dernier concept : une spcication de conversion peut tre associe une expression comme g/f ou mme une constante.
eils Cons

ne pas faire Coder plusieurs lignes de texte dans une seule instruction printf(). Le programme sera plus facile lire si vous codez plusieurs instructions printf() contenant chacune une ligne de texte. Omettre le caractre de retour la ligne quand vous afchez plusieurs lignes avec des instructions printf() diffrentes.

Syntaxe de la fonction printf()


#include <stdio.h> printf(chane-format [, arguments,...]);

La fonction printf() peut recevoir des arguments. Ceux-ci doivent correspondre, en nombre et en type, aux spcications de conversion contenues dans la chane format. printf() envoie les informations mises en forme vers la sortie standard (lcran). Pour quun programme puisse appeler la fonction printf(), le chier standard dentres/ sorties stdio.h doit tre inclus. La chane format peut contenir des ordres de contrle. Le Tableau 7.1 donne la liste des ordres les plus souvent utiliss. Voici quelques exemples dappels de la fonction printf(): Exemple 1 : code
#include <stdio.h> int main() { printf("Voici un exemple de message!"); return 0; }

Exemple 1 : rsultat
Voici un exemple de message!

http://fribok.blogspot.com/

Exemple 2 : code
printf("Cela affiche un caractre,%c\nun nombre, %d\nun nombre virgule \ flottante,%f", z, 123, 456.789);

Exemple 2 : rsultat
Cela affiche un caractre, z un nombre, 123 un nombre virgule flottante, 456.789

La fonction puts()
La fonction puts() permet aussi dafcher du texte lcran, mais pas de variable. Elle reoit une chane de caractres en argument et lenvoie vers la sortie standard (cran), en ajoutant automatiquement un retour la ligne la n du message. Linstruction :
puts("Hello, world.");

aura le mme rsultat que linstruction :


printf("Hello, world.\n");

Vous pouvez inclure des ordres de contrle dans une chane passe la fonction puts(), ils ont la mme signication que pour la fonction printf(). Si votre programme utilise puts(), vous devez inclure le chier en-tte stdio.h.
eils Cons

faire Utiliser la fonction puts() plutt que printf() si le texte afcher ne contient pas de variable. ne pas faire Utiliser des spcications de conversion dans une chane passe la fonction puts().

Syntaxe de la fonction puts()


#include <stdio.h> puts (chane);

puts() est une fonction qui envoie une chane de caractres vers la sortie standard (cran). Pour lutiliser, vous devez inclure le chier en-tte stdio.h dans votre programme. La chane format de puts() peut contenir tous les ordres de contrle de printf() (voir Tableau 7.1). Elle sera afche lcran avec lajout dun retour la ligne la n du message.

http://fribok.blogspot.com/

Voici quelques exemples dappels de cette fonction avec leurs rsultats lcran : Exemple 1 : code
puts("Cela est imprim avec la fonction puts()!");

Exemple 1 : rsultat
Cela est imprim avec la fonction puts()!

Exemple 2 : code
puts("Premire lignedu message. \nSeconde lignedu message."); puts("Voici la troisime ligne."); puts("Si nous avions utilis printf(), ces 4 lignesauraient t \ sur 2 lignes!");

Exemple 2 : rsultat
Premire lignedu message. Seconde lignedu message. Voici la troisime ligne. Si nous avions utilis printf(), ces 4 lignesauraient t sur 2 lignes!

Lecture de donnes numriques avec scanf()


Limmense majorit des programmes a besoin dafcher des donnes lcran et, de la mme faon, de rcuprer des donnes partir du clavier. La faon la plus souple de le faire est dutiliser la fonction scanf(). La fonction scanf() lit les donnes entres au clavier en fonction du format spci, et les attribue une ou plusieurs variables du programme. Cette fonction utilise, comme printf(), une chane format qui dcrit le format des donnes qui seront lues. La chane format contient les mmes spcications de conversion que pour la fonction printf(). Par exemple :
scanf("%d", &x);

Cette instruction lit un entier dcimal et lattribue la variable entire x. De la mme faon, linstruction suivante lit une valeur avec virgule ottante et lattribue la variable taux:
scanf("%f", &taux);

Le symbole & est loprateur dadresse du langage C. Ce concept est expliqu en dtail dans le Chapitre 9. Retenez simplement que vous devez le placer devant le nom de chaque variable.

http://fribok.blogspot.com/

La chane reue en argument par scanf() peut contenir un nombre illimit de variables. Linstruction suivante lit une variable entire et une autre virgule ottante, et les attribue respectivement aux variables x et taux (sans oublier le signe &) :
scanf("%d%f", &x, &taux);

Quand la chane argument de scanf() contient plus dune variable, un espace doit sparer les diffrents champs entrs au clavier. Cet espace peut tre constitu dun ou plusieurs blancs, de tabulations ou de lignes blanches. Cela vous donne une grande libert sur la faon de saisir vos donnes. Chaque fois que scanf() lit un champ, elle le compare la spcication de conversion correspondante. En rponse linstruction scanf() prcdente, vous auriez pu taper :
1012.45

ou bien :
10 12.45

ou encore :
10 12.45

Comme pour les autres fonctions de ce chapitre, lutilisation de scanf() implique celle du chier en-tte stdio.h. Listing 7.3 : Lecture de valeurs numrique avec scanf()
1: /* Exemple dutilisation de la fonction scanf() */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: #define QUIT 4 6: 7: int choix_menu(void); 8: 9: int main() 10: { 11:intchoix= 0; 12:intvar_int= 0; 13:float var_float = 0.0; 14:unsigned var_unsigned = 0; 15: 16:while(choix!= QUIT) 17:{ 18:choix = choix_menu(); 19:

http://fribok.blogspot.com/

Listing 7.3 : Lecture de valeurs numrique avec scanf() (suite)


20:if(choix == 1) 21:{ 22:puts("\nEntrez un entier dcimal sign (ex 123)"); 23:scanf("%d", &var_int); 24:} 25:if (choix == 2) 26:{ 27:puts("\nEntrez un nombre avec virgule flottante (ex 1.23)"); 28:scanf("%f", &var_float); 29:} 30:if (choix == 3) 31:{ 32:puts("\nEntrez un entier dcimal non sign (ex 123)"); 33:scanf("%u", &var_unsigned); 34:} 35:} 36:printf("\nVos valeurs sont: int:%dfloat:%funsigned:%u\n", 37:var_int, var_float, var_unsigned); 38:exit(EXIT_SUCCESS); 39: } 40: 41: int choix_menu(void) 42: { 43:int selection = 0; 44: 45:do 46:{ 47:puts("\n1 - Lire un entier dcimal sign"); 48:puts("2 - Lire un nombre avec virgule flottante"); 49:puts("3 - Lire un entier dcimal non sign"); 50:puts("4 - Sortir"); 51:puts("\nEntrez votre choix:"); 52: 53:scanf("%d", &selection); 54: 55:}while (selection < 1 || selection > 4); 56: 57:return selection; 58: } 1 - Lire un entier dcimal sign 2 - Lire un nombre avec virgule flottante 3 - Lire un entier dcimal non sign 4 - Sortir Entrez votre choix: 1 Entrez un entier dcimal sign (ex 123) 123 1 - Lire un entier dcimal sign 2 - Lire un nombre avec virgule flottante

http://fribok.blogspot.com/

3 - Lire un entier dcimal non sign 4 - Sortir Entrez votre choix: 3 Entrez un entier dcimal non sign (ex 123) 321 1 2 3 4 Lire un entier dcimal sign Lire un nombre avec virgule flottante Lire un entier dcimal non sign Sortir

Entrez votre choix: 2 Entrez un nombre avec virgule flottante (ex 1.23) 1231.123 1 2 3 4 Lire un entier dcimal sign Lire un nombre avec virgule flottante Lire un entier dcimal non sign Sortir

Entrez votre choix: 4 Vos valeurs sont: int: 123 float: 1231.123047 unsigned: 321

Analyse Le programme du Listing 7.3 utilise le mme systme de menu que celui du Listing 7.1. Les lignes 41 58 ont t quelque peu modies : la fonction puts() remplace la fonction printf() puisque le message ne contient pas de variable. Le caractre \n qui est ajout automatiquement par scanf() a disparu des lignes 48 50. La ligne 55 a t transforme pour les 4 options de notre menu. La ligne 53 reste inchange : scanf() lit une valeur dcimale et la stocke dans la variable selection. La fonction renvoie alors selection au programme appelant en ligne 57. Les programmes du Listing 7.1 et du Listing 7.3 ont la mme structure de fonction main(). Une instruction if value le choix de lutilisateur (valeur retourne par la fonction choix menu()) pour que le programme afche le message correspondant. La fonction scanf() lit le nombre entr par lutilisateur. Les lignes 23, 28 et 33 sont diffrentes parce que les variables lues ne sont pas du mme type. Les lignes 12 14 contiennent les dclarations de ces variables. Quand lutilisateur dcide de quitter le programme, celui-ci envoie un dernier message contenant la dernire valeur de chaque type qui a t lue. Si lutilisateur na pas entr de valeur pour lun dentre eux, cest la valeur dinitialisation 0 qui est afche (lignes 12,

http://fribok.blogspot.com/

13, 14). Nous pouvons faire une dernire remarque concernant les lignes 20 34 : une structure de type if...else aurait t plus approprie. Le Chapitre 14, qui approfondira le sujet de la communication avec lcran, le clavier et limprimante, vous montrera que linstruction idale est une nouvelle instruction de contrle : switch.
eils Cons

faire Utiliser conjointement printf() ou puts() avec scanf(). Les deux premires fonctions permettent de demander lutilisateur les variables que vous voulez lire. ne pas faire Ne pas ajouter loprateur dadresse (&) en codant les variables de scanf().

Syntaxe de la fonction scanf()


#include <stdio.h> scanf (chane format[ , arguments,...]);

La fonction scanf() lit des donnes entres au clavier et utilise les spcications de conversion de la chane format pour les attribuer aux diffrents arguments. Ces arguments reprsentent les adresses des variables plutt que les variables elles-mme. Ladresse dune variable numrique est reprsente par le nom de la variable prcd du signe (&). Un programme qui utilise scanf() doit faire appel au chier en-tte stdio.h. Exemple 1
int x, y, z; scanf("%d%d%d", &x, &y, &z);

Exemple 2
#include <stdio.h> int main() { float y; int x; puts("Entrez un nombre entier puis un nombre virgule flottante:"); scanf("%f%d", &y, &x); printf("\nVous avez tap%f et%d, y, x); return 0; }

http://fribok.blogspot.com/

Rsum
En combinant les trois fonctions printf(), puts() et scanf(), et les instructions de contrle que nous avons tudies aux chapitres prcdents, vous avez tous les outils ncessaires pour crire des programmes simples. Lafchage dinformations sur lcran se fait partir de puts() et printf(). La fonction puts() afche du texte exclusivement, la fonction printf() peut y ajouter des variables. Elles utilisent toutes deux des ordres de contrle qui permettent dafcher les caractres spciaux et de mettre en forme le message envoy. La fonction scanf() lit au clavier une ou plusieurs valeurs numriques et les interprte en fonction de la spcication de conversion correspondante. Chaque valeur est attribue une variable du programme.

Q&R
Q Pourquoi utiliser puts() alors que printf() est moins restrictive ? R La fonction printf() tant plus complte, elle consomme plus de ressources. Quand vos programmes vont se dvelopper, les ressources vont devenir pr-cieuses. Il sera alors avantageux dutiliser puts() pour du texte. En rgle gnrale, utilisez plutt la ressource disponible la plus simple. Q Pourquoi faut-il inclure le chier stdio.h quand on veut utiliser printf(), puts(), ou scanf()? R Le chier stdio.h contient le prototype des fonctions standards dentre/sortie ; printf(), puts() et scanf() en font partie. Q Que se passe-t-il si joublie loprateur dadresse (&) dune variable de la fonction scanf()? R Si vous oubliez cet oprateur, le rsultat est totalement imprvisible. Au lieu de stocker la valeur reue dans la variable, scanf() va la stocker un autre endroit de la mmoire. Les consquences peuvent tre insigniantes ou entraner larrt total de lordinateur. Vous comprendrez pourquoi aprs ltude des Chapitres 9 et 13.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

http://fribok.blogspot.com/

Quiz
1. Quelle est la diffrence entre puts() et printf()? 2. Quel chier devez-vous inclure dans votre programme quand vous utilisez printf()? 3. Que font les ordres de contrle suivants : a) \\. b) \b. c) \n. d) \t. e) \a. 4. Quelle spcication de conversion faut-il utiliser si on veut afcher : a) Une chane de caractres. b) Un entier dcimal sign. c) Un nombre dcimal avec virgule ottante. 5. Quel est le rsultat des squences suivantes dans un texte pass puts()? a) b. b) \b. c) \. d) \\.

Exercices
ce Astu

partir de ce chapitre, certains exercices vous demandent dcrire un programme complet pour effectuer un certain travail. En langage C, il y a toujours plusieurs solutions un problme donn : les rponses fournies en Annexe G ne sont pas les seules bonnes solutions. Si le code que vous avez dvelopp ne gnre pas derreur et donne le rsultat recherch, vous avez trouv une solution. Si vous rencontrez des difcults, la solution donne en exemple pourra vous aider.

1. crivez deux instructions qui provoquent un retour la ligne, laide des fonctions printf() et puts(). 2. crivez la fonction scanf() qui lira au clavier un caractre, un entier dcimal non sign, puis un autre caractre.

http://fribok.blogspot.com/

3. crivez les instructions qui permettront de lire une valeur entire et de lafcher lcran. 4. Transformez le code de lexercice 3 pour quil naccepte que des valeurs paires. 5. Modiez lexercice 4 pour quil renvoie des valeurs jusqu ce que le nombre 99 soit lu, ou que lon ait lu la sixime valeur paire. Stockez les six nombres dans un tableau. 6. Transformez lexercice 5 en code excutable. Ajoutez une fonction qui afche les valeurs du tableau, en les sparant par une tabulation, sur une seule ligne. 7. CHERCHEZ LERREUR :
printf("Jacques a dit, "Levez le bras droit!"");

8. CHERCHEZ LERREUR :
int lire_1_ou_2(void) { int reponse = 0; while (reponse < 1 || reponse > 2) { printf(Entrez 1 pour oui, 2 pour non); scanf("%f", reponse); } return reponse; }

9. Compltez le Listing 7.1 pour que la fonction afche le Tableau 7.1 en entier. 10. crivez un programme qui lira deux nombres avec virgule ottante au clavier, puis afchera leur produit. 11. crivez un programme qui lira dix valeurs entires au clavier et afchera leur somme. 12. crivez un programme qui lira des entiers au clavier pour les stocker dans un tableau. Lentre des donnes sarrtera si lutilisateur tape 0 ou si le tableau est complet. Le programme afchera ensuite la plus petite et la plus grande valeur du tableau. Ce problme est difcile, car nous navons pas ni dtudier les tableaux. Si vous ne trouvez pas de solution, essayez de faire cet exercice aprs avoir lu le Chapitre 8.

Info

http://fribok.blogspot.com/

Rvision de la Partie I

Cette premire partie vous a familiaris avec la programmation : coder, compiler, effectuer la liaison et excuter un programme. Le programme qui suit reprend de nombreux sujets dj tudis.
La philosophie de cette section diffre de celle des exemples pratiques. Vous ne trouverez pas dlments inconnus dans le programme. Et celui-ci est suivi dune analyse. Les Parties II et III sont aussi suivies de sections de ce type. Les indications dans la marge vous renvoient au chapitre qui prsente les concepts de la ligne. Vous pourrez ainsi retrouver les informations correspondantes.

Info

Listing rvision de la Partie I


Ch. 02
1:/* Nom du programme: week1.c*/ 2:/*Ce programme permet de saisir lge et le revenu */ 3:/*de 100 personnes au maximum. Il affiche ensuite */ 4:/*les rsultats obtenus*/ 5:/*-----------------------------------------------------*/ 6:/*---------------------------*/ 7:/* Fichiers inclus*/ 8:/*---------------------------*/ 9: #include <stdio.h> 10: #include <stdlib.h> 11: /*---------------------------*/ 12: /* Dfinition des constantes */ 13: /*---------------------------*/

Ch. 02 Ch. 02

http://fribok.blogspot.com/

Ch. 02

Ch. 02

Ch. 03

Ch. 02

Ch. 05

Ch. 02 Ch. 05 Ch. 04 Ch. 05 Ch. 05 Ch. 04 Ch. 07 Ch. 02

Ch. 05

14: 15: #define MAX100 16: #define OUI1 17: #define NON0 18: 19: /*---------------------------*/ 20: /*Variables */ 21: /*---------------------------*/ 22: 23: long revenu[MAX];/* pour stocker les revenus */ 24: int mois[MAX], jour[MAX], annee[MAX]; /* pour les dates de naissance */ 25: int x, y, ctr;/* compteurs */ 26: intcont;/* contrle du programme */ 27: longtotal_mois, grand_total;/* calcul des totaux */ 28: 29: /*---------------------------*/ 30: /* Prototypes des fonctions*/ 31: /*---------------------------*/ 32: 33: int main(void); 34: int affiche_instructions(void); 35: void lecture(void); 36: void affiche_result(void); 37: int continuer(void); 38: 39: /*---------------------------*/ 40: /* Dbut du programme */ 41: /*---------------------------*/ 42: int main(void) 43: { 44:cont = affiche_instructions(); 45: 46:if (cont == OUI) 47:{ 48:lecture(); 49:affiche_result(); 50:} 51:else 52:printf("\nProgramme interrompu par lutilisateur!\n\n"); 53: exit(EXIT_SUCCESS); 54: } 55: /*-----------------------------------------------------------*/ 56: /* Fonction: affiche_instructions() */ 57: /* objectif: affiche le mode demploi du programme et */ 58: /*demande lutilisateur dentrer 0 pour */ 59: /*sortir ou 1 pour continuer*/ 60: /* Valeurs renvoyes: NONsi lutilisateur tape 0 */ 61: /*OUIsi lutilisateur tape un nombre */ 62: /*diffrent de 0 */ 63: /*-----------------------------------------------------------*/ 64: 65: int affiche_instructions(void)

http://fribok.blogspot.com/

Ch. 07

Ch. 05 Ch. 05 Ch. 02

Ch. 05 Ch. 06 Ch. 07 Ch. 06 Ch. 07 Ch. 07 Ch. 06 Ch. 06 Ch. 07 Ch. 07 Ch. 06 Ch. 06 Ch. 07 Ch. 07 Ch. 06 Ch. 07 Ch. 05

66: { 67:printf("\n\n"); 68:printf("\nCe programme vous permet de saisir le revenu et"); 69:printf("\nla date de naissance de 99 personnes maxi, pour"); 70:printf("\ncalculer et afficher le total des revenus mois par mois,"); 71:printf("\nle total annuel des revenus, et la moyenne de ces revenus."); 72:printf("\n"); 73: 74:cont = continuer(); 75: 76:return(cont); 77: } 78: /*-----------------------------------------------------------*/ 79: /* Fonction: lecture() */ 80: /* Objectif: Cette fonction lit les donnes entres par */ 81: /*lutilisateur jusqu ce que 100 personnes soient */ 82: /*enregistres, ou que lutilisateur tape 0 pour le mois*/ 83: /* Valeurs renvoyes: aucune */ 84: /* Remarque: Cela permet dentrer 0/0/0 dans le champ */ 85: /*anniversaire si lutilisateur ne le connat pas. */ 86: /*Celaautorise galement 31 jours pour tous les mois*/ 87: /*-----------------------------------------------------------*/ 88: 89: void lecture(void) 90: { 91:for (cont = OUI, ctr = 0; ctr < MAX && cont == OUI; ctr++) 92:{ 93:printf("\nEntrez les informations pour la personne no%d", ctr+1); 94:printf("\n\tDate de naissance:"); 95: 96:do 97:{ 98:printf("\n\tMois (0 - 12): "); 99:scanf("%d", &mois[ctr]); 100:}while (mois[ctr] < 0 || mois[ctr] > 12); 101: 102:do 103:{ 104:printf("\n\tJour (0 - 31): "); 105:scanf("%d", &jour[ctr]); 106:}while (jour[ctr] < 0 || jour[ctr] >31); 107: 108:do 109:{ 110:printf("\n\tAnne (0 - 1994): "); 111:scanf("%d", &annee[ctr]); 112:}while (annee[ctr] < 0 || annee[ctr] > 1994); 113: 114:printf("\nEntrez le revenu annuel (en francs): "); 115:scanf("%ld%", &revenu[ctr]); 116: 117:cont = continuer(); 118:}

http://fribok.blogspot.com/

Ch. 07 Ch. 02

Ch. 05 Ch. 04 Ch. 07

Ch. 06 Ch. 04 Ch. 06 Ch. 04 Ch. 04 Ch. 07 Ch. 04 Ch. 07

Ch. 02

Ch. 05 Ch. 07 Ch. 06 Ch. 07

119: /* La valeur de ctr correspond au nombre de personnes enregistres*/ 120: } 121: /*----------------------------------------------------------*/ 122: /* Fonction: affiche_result()*/ 123: /* Objectif: affiche le rsultat des calculs lcran*/ 124: /* Valeurs renvoyes: aucune*/ 125: /*----------------------------------------------------------*/ 126: 127: void affiche_result() 128: { 129:grand_total = 0; 130:printf("\n\n\n");/* on saute quelques lignes */ 131:printf("\nSalaires"); 132:printf("\n========"); 133: 134:for (x = 0; x <= 12; x++) /* pour chaque mois */ 135:{ 136:total_mois = 0; 137:for (y = 0; y < ctr; y++) 138:{ 139:if(mois[y] == x) 140:total_mois += revenu[y]; 141:} 142:printf("\nLe total pour le mois%d est%ld", x, total_mois); 143:grand_total += total_mois; 144:} 145:printf("\n\n\nLe total des revenus est de%ld", grand_total); 146:printf("\nLa moyenne des revenus est de%ld", grand_total/ctr); 147: 148:printf("\n\n* * * fin des rsultats * * *"); 149: } 150: /*-----------------------------------------------------------*/ 151: /* Fonction: continuer()*/ 152: /* Objectif: cette fonction demande lutilisateur sil */ 153: /* veut continuer */ 154: /* Valeurs renvoyes:OUIsi lutilisateur dsire poursuivre*/ 155: /*NON si lutilisateur veut sortir*/ 156: /*-----------------------------------------------------------*/ 157: int continuer(void) 158: { 159:printf("\n\nVoulez-vous continuer? (0=non / 1=oui):"); 160:scanf("%d", &x); 161: 162:while (x < 0 || x > 1) 163:{ 164:printf("\n%d est erron!", x); 165:printf("\nEntrez 0 pour sortir ou 1 pour continuer:"); 166:scanf("%d", &x); 167:} 168:if (x == 0) 169:return(NON); 170:else 171:return(OUI); 172: }

http://fribok.blogspot.com/

Analyse Quand vous aurez rpondu aux quiz et exercices des Chapitres 1 et 2, vous saurez saisir et compiler le code de ce programme. Nous nous sommes placs en mode rel de travail en commentant abondamment les diffrentes parties, et en particulier, le dbut du programme et chaque fonction majeure. Les lignes 1 5 contiennent le nom et le descriptif du programme. Certains programmeurs ajouteraient des informations comme le nom de lauteur du programme, le compilateur utilis avec son numro de version, les bibliothques lies au programme et sa date de cration. Les commentaires prcdant chaque fonction indiquent la tche ralise par cette fonction, ventuellement le type de valeur renvoye ou les conventions dappel. Les commentaires du dbut vous indiquent que vous pouvez saisir des renseignements concernant 100 personnes au maximum. Avant de commencer la lecture des donnes tapes par lutilisateur, le programme appelle affiche instructions() (ligne 44). Cette fonction afche le descriptif du programme et demande lutilisateur sil est daccord pour continuer. Le code de cette fonction utilise printf() (lignes 67 72) que vous avez tudie au Chapitre 7. La fonction continuer() en lignes 157 172 utilise quelques notions tudies en n de partie. La ligne 159 demande lutilisateur sil veut continuer. Linstruction de contrle while vrie la rponse et renvoie le message jusqu obtention dune rponse valide : 0 ou 1. Linstruction if else renvoie alors au programme la variable OUI ou NON. Le principal travail ralis par le programme dpend de deux fonctions : lecture() et affiche(). La premire vous demande dentrer les donnes pour les stocker dans les tableaux dclars en dbut de programme. Linstruction for de la ligne 91 lit les donnes jusqu ce que cont soit diffrent de la constante OUI (renvoye par la fonction conti nue()) ou que la valeur du compteur ctr soit suprieure ou gale la valeur MAX (nombre maximum dlments dans les tableaux). Le programme contrle et valide chaque information saisie. Les lignes 96 100, par exemple, demandent lutilisateur dentrer un numro de mois. Si la valeur saisie nest pas un entier compris entre 0 et 12 inclus, le message est afch de nouveau. La ligne 117 appelle la fonction continuer() pour savoir si lutilisateur dsire continuer ou arrter. Si la rponse est 0, ou si le nombre maximum denregistrements est atteint (MAX), lexcution se poursuit en ligne 49 avec lappel de la fonction affiche result(). La fonction affiche result() des lignes 127 149 envoie un compte rendu des enregistrements lcran. Une boucle for imbrique permet le calcul du total des revenus mois par mois et du total gnral. Ce programme illustre les sujets tudis au cours de cette premire partie. Vos connaissances concernant le langage C sont encore limites, mais vous tes maintenant capable dcrire vos propres programmes.

http://fribok.blogspot.com/

Tour dhorizon de la Partie II

Votre premire partie dtude de la programmation en langage C est termine. Vous tes maintenant familiaris avec lditeur pour saisir vos programmes, et le compilateur pour crer le code excutable correspondant.

Ce que vous allez apprendre


Cette seconde partie dapprentissage couvre de nombreux concepts qui constituent le cur du langage C. Vous allez apprendre utiliser les tableaux numriques et les tableaux de caractres, et crer des structures pour grouper diffrents types de variables. Cette deuxime partie introduit de nouvelles instructions de contrle, et fournit un descriptif dtaill de diverses fonctions. Les Chapitres 9 et 12 traitent de sujets trs importants pour comprendre les principes du dveloppement en langage C : les pointeurs et la porte des variables. Aprs les programmes simples de la premire partie, les informations fournies par la deuxime vous permettront dcrire des programmes plus complexes pour accomplir presque toutes les tches.

http://fribok.blogspot.com/

8
Utilisation des tableaux numriques
Les tableaux reprsentent un type de stockage de donnes souvent utilis en langage C. Le Chapitre 6 vous en a donn un bref aperu. Aujourdhui, vous allez tudier : La dnition dun tableau Les tableaux numriques une ou plusieurs dimensions La dclaration et linitialisation des tableaux

http://fribok.blogspot.com/

Dnition
Un tableau reprsente un ensemble demplacements mmoire qui portent le mme nom et contiennent le mme type de donnes. Chacun de ces emplacements est un lment du tableau. Pour dmontrer lutilit des tableaux, le mieux est de prendre un exemple. Si vous gardez une trace de vos frais professionnels pour 1998 en classant vos reus mois par mois, vous pourriez constituer un dossier par mois. Toutefois, il serait srement plus pratique davoir un seul dossier comportant douze compartiments. Adaptons cet exemple la programmation. Supposons que vous criviez un programme pour le calcul de vos frais professionnels. Ce programme pourrait dclarer douze variables diffrentes, correspondant aux douze mois de lanne. Un bon programmeur utilisera plutt un tableau de douze lments, o le total de chaque mois est stock dans llment correspondant. La Figure 8.1 vous montre la diffrence entre lutilisation de variables individuelles et un tableau.
Figure 8.1 Les variables sont lquivalent de dossiers indi-viduels, alors que le tableau reprsente un dossier ayant de multiples compartiments.

Variables individuelles

Tableau

Les tableaux une dimension


Un tableau une dimension ne possde quun seul index. Un index est le nombre entre crochets qui suit le nom du tableau. Il indique le nombre dlments du tableau. Dans le cas du programme de calcul de vos frais professionnels, par exemple, vous pourriez dclarer un tableau de type float:
float depenses[12];

Le tableau sappelle depenses et contient 12 lments, chacun deux tant lquivalent dune variable de type float. Un lment de tableau peut contenir nimporte quel type de

http://fribok.blogspot.com/

donne du langage C. Les lments sont toujours numrots en commenant 0 ; ceux de notre exemple seront donc numrots de 0 11. Pour chaque dclaration de tableau, le compilateur rserve un bloc de mmoire dune taille sufsante pour contenir la totalit des lments. Ceux-ci seront stocks squentiellement comme le montre la Figure 8.2.
int tableau[10]; Tableau[0] Tableau[1] Tableau[2] Tableau[3] Tableau[8] Tableau[9]

Figure 8.2 Les lments de tableau sont stocks en mmoire de faon squentielle.

Comme pour les variables simples, lemplacement de la dclaration du tableau dans le code source est important. Il dtermine la faon dont le programme pourra utiliser le tableau. En attendant que le Chapitre 12 vous donne les informations ncessaires, positionnez vos dclarations avec les autres dclarations de variables, avant le dbut de la fonction principale main(). Un lment de tableau sutilise comme une variable isole de mme type. Il est rfrenc au moyen du nom de tableau suivi de son index entre crochets. Linstruction suivante, par exemple, stocke la valeur 89,95 dans le second lment de notre tableau depenses:
depenses[1] = 89.95;

De la mme faon, linstruction :


depenses[10] = depenses[11];

stocke un exemplaire de la valeur contenue dans llment de tableau depenses[11] dans llment de tableau depenses[10]. Lindex du tableau peut tre une constante comme dans notre exemple, mais aussi une expression, une variable entire, ou mme un autre lment de tableau. Voici quelques exemples :
float depenses[100]; int a[10]; /* Des instructions peuvent prendre place ici */ depenses[i]=100;/* i est une variable entire */ depenses[2+3] = 100;/* quivalent de depenses[5] */ depenses[a[2]] = 100;/* a[] est un tableau contenant des entiers*/

http://fribok.blogspot.com/

La dernire ligne ncessite un complment dinformation. Si a[] est un tableau contenant des entiers, et que la valeur 8 est stocke dans llment a[2], crire :
depenses[ a[2] ]

a la mme signication que :


depenses[8]

Noubliez pas que, dans un tableau de n lments, lindex est compris entre 0 et n1. Lemploi de la valeur dindex n ne sera pas dcel par le compilateur, mais cela provoquera des erreurs dans les rsultats du programme.
ntion Atte

Les lments dun tableau commencent 0 et non 1. Un tableau contenant 10 lments, par exemple, commencera 0 et se terminera 9.

Vous pouvez, pour vous simplier la tche, adresser les lments dun tableau en commenant 1 jusqu n. La mthode la plus simple consiste dclarer un tableau avec n + 1 lments et den ignorer le premier. Listing 8.1 : depenses.c illustre lutilisation dun tableau
1: /* depenses.c -- Exemple dutilisation dun tableau */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: /*Dclaration du tableau pour enregistrer les dpenses, */ 6: /* et dune variable compteur */ 7: float depenses[13]; 8: int compteur; 9: 10: int main() 11: { 12: /* Lecture des donnes au clavier et stockage dans le tableau */ 13: 14:for (compteur = 1; compteur < 13; compteur++) 15:{ 16:printf("Entrez les dpenses pour le mois%d: ", compteur); 17:scanf("%f", &depenses[compteur]); 18:} 19: 20: /* Affichage du contenu du tableau */ 21: 22:for (compteur = 1; compteur < 13; compteur++) 23:{ 24:printf("Mois%d =%.2fF\n", compteur, depenses[compteur]); 25:} 26:exit(EXIT_SUCCESS); 27:}

http://fribok.blogspot.com/

Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez

les les les les les les les les les les les les

dpenses dpenses dpenses dpenses dpenses dpenses dpenses dpenses dpenses dpenses dpenses dpenses

pour pour pour pour pour pour pour pour pour pour pour pour

le le le le le le le le le le le le

mois 1: 100 mois 2: 200.12 mois 3: 150.50 mois 4: 300 mois 5: 100.50 mois 6: 34.25 mois 7: 45.75 mois 8: 195.00 mois 9: 123.45 mois 10: 111.11 mois 11: 222.20 mois 12: 120.00

Mois 1 = 100.00F Mois 2 = 200.12F Mois 3 = 150.50F Mois 4 = 300.00F Mois 5 = 100.50F Mois 6 = 34.25F Mois 7 = 45.75F Mois 8 = 195.00F Mois 9 = 123.45F Mois 10 = 111.11F Mois 11 = 222.20F Mois 12 = 120.00F

Analyse Quand vous excutez ce programme, un message vous demande dentrer les dpenses correspondant aux douze mois de lanne ; les valeurs saisies sont alors afches lcran. La ligne 1 contient un descriptif du programme. Inclure le nom du programme dans les commentaires den-tte pourra vous tre trs utile si par exemple vous imprimez le programme pour le modier. La ligne 5 annonce la dclaration des diffrentes variables, et la ligne 7 contient la dclaration dun tableau de 13 lments. Ce programme na besoin que de 12 lments (pour les 12 mois de lanne), mais nous en avons dclar 13. La boucle for des lignes 14 18 ignore llment 0. La variable compteur dclare en ligne 8 sera utilise comme compteur et comme index pour le tableau. La fonction principale main() commence en ligne 10. Une boucle for demande lutilisateur la valeur des dpenses pour chacun des 12 mois. La fonction scanf() de la ligne 17 range cette valeur dans un lment du tableau. %f est utilis parce que le tableau depen ses a t dclar avec le type float en ligne 7. Loprateur dadresse (&) est plac devant llment de tableau, exactement comme si ctait une variable float.

http://fribok.blogspot.com/

Les lignes 22 25 contiennent une seconde boucle for qui afche les valeurs du tableau. %.2f permet dafcher un nombre avec deux chiffres aprs la virgule. Le Chapitre 14 traite de ce type de commande qui permet de mettre en forme le texte afcher.
eils Cons

faire Utiliser un tableau plutt que crer plusieurs variables pour stocker le mme type de donnes. ne pas faire Noubliez pas que lindex dun tableau commence la valeur 0.

Les tableaux plusieurs dimensions


Un tableau plusieurs dimensions possde plusieurs index. Un tableau deux dimensions en a deux, un tableau trois dimensions en a trois, etc. En langage C, il ny a pas de limite au nombre de dimensions quun tableau peut avoir. Vous pouvez, par exemple, crire un programme qui joue aux checs. Lchiquier contient 64 carrs sur huit lignes et huit colonnes. Votre programme pourra le reprsenter sous forme de tableau deux dimensions de la faon suivante :
int chiquier[8][8];

Le tableau ainsi cr a 64 lments : chiquier[0][0], chiquier[0][1], chi quier[0][2] chiquier[7][6], chiquier[7][7]. La Figure 8.3 reprsente la structure de ce tableau.
Figure 8.3 Un tableau deux dimensions a une structure en lignescolonnes.
int echiquier[8][8]; echiquier[0][0] echiquier[1][0] echiquier[2][0] echiquier[0][1] echiquier[1][1] echiquier[2][1] echiquier[0][7] echiquier[1][7] echiquier[2][7]

echiquier[7][0]

echiquier[7][1]

echiquier[7][7]

On peut aussi imaginer un tableau trois dimensions comme un cube. Quel que soit le nombre de ses dimensions, un tableau est stock en mmoire de faon squentielle.

http://fribok.blogspot.com/

Le nom et la dclaration des tableaux


Les rgles concernant lattribution dun nom un tableau sont les mmes que celles qui rgissent les noms de variables (voir Chapitre 3). Un nom de tableau doit tre unique : il ne doit pas avoir t attribu prcdemment un autre tableau, une variable ou une constante, etc. Une dclaration de tableau a la mme forme quune dclaration de variable, mis part le fait que le nombre dlments du tableau doit apparatre entre crochets immdiatement aprs son nom. Dans la dclaration, le nombre dlments du tableau peut tre une constante littrale ou une constante symbolique cre avec lordre #define. Exemple :
#define MOIS 12 int tableau[MOIS];

Linstruction qui suit est quivalente :


int tableau[12]; const int MOIS = 12;

Listing 8.2 : Le programme notes.c stocke dix notes dans un tableau


1: /* notes.c--Echantillon dun programme qui utilise un tableau */ 2: /* pour lire 10 notes et en calculer la moyenne */ 3: #include <stdio.h> 4: #include <stdlib.h> 5: 6: #define MAX_NOTE 100 7: #define ETUDIANTS10 8: 9: int notes[ETUDIANTS]; 10: 11: int idx; 12: int total = 0;/* pour le calcul de la moyenne */ 13: 14: int main() 15: { 16:for(idx = 0; idx < ETUDIANTS; idx++) 17:{ 18: printf("Entrez la note de l\tudiant numero%d: ", idx+1); 19: scanf("%d", &notes[idx]); 20: 21: while (notes[idx] > MAX_NOTE) 22: { 23: printf("\nLa note maximum est%d", MAX_NOTE); 24: printf("\nEntrez une note correcte: "); 25: scanf("%d", &notes[idx]); 26:}

http://fribok.blogspot.com/

Listing 8.2 : Le programme notes.c stocke dix notes dans un tableau (suite)
27: 28: total += notes[idx]; 29:} 30: 31:printf("\n\nLa moyenne des notes est%d\n", 32:(total / ETUDIANTS)); 33:exit(EXIT_SUCCESS); 34: } Entrez Entrez Entrez Entrez la la la la note note note note de de de de ltudiant ltudiant ltudiant ltudiant numro numro numro numro 1: 2: 3: 4: 95 100 60 105

La note maximum est 100 Entrez une note correcte: 100 Entrez la note de ltudiant numro 5: Entrez la note de ltudiant numro 6: Entrez la note de ltudiant numro 7: Entrez la note de ltudiant numro 8: Entrez la note de ltudiant numro 9: Entrez la note de ltudiant numro 10: La moyenne des notes est 73

25 0 85 85 95 85

Analyse Ce programme demande lutilisateur dentrer les notes de dix tudiants, puis il en afche la moyenne. Le tableau du programme sappelle notes (ligne 9). Deux constantes sont dnies aux lignes 6 et 7 : MAX NOTE et ETUDIANTS. La valeur de ces constantes pourra changer facilement. Celle de la constante ETUDIANTS tant 10, cela reprsente aussi le nombre dlments du tableau. La variable idx, abrviation dindex, est utilise comme compteur et comme index du tableau. La variable total contiendra la somme de toutes les notes. Le travail principal du programme se fait aux lignes 16 29 avec la boucle for. La variable idx est initialise 0, le premier indice du tableau ; elle est incrmente chaque excution de la boucle qui lit la note dun tudiant (lignes 18 et 19). Remarquez que la ligne 18 ajoute 1 la valeur didx de faon compter de 1 10 plutt que de 0 9 : la premire note est stocke en notes[0], mais on a demand lutilisateur la note de ltudiant numro 1. Les lignes 21 26 contiennent une boucle while imbrique dans la boucle for. Cette boucle permet de vrier la validit de la note donne par lutilisateur. Si elle est suprieure MAX_NOTE, un message demande lutilisateur de retaper une note correcte.

http://fribok.blogspot.com/

La ligne 28 additionne les notes chaque excution de la boucle, et la ligne 31 afche la moyenne de ces notes en n dexcution du programme.
eils Cons

faire Utiliser des instructions #define pour crer les constantes qui permettront de dclarer les tableaux. Il sera ainsi facile de changer la valeur du nombre dlments. Dans le programme notes.c, par exemple, vous pouviez changer le nombre dtudiants dans linstruction #define sans avoir changer le reste du programme. ne pas faire Crer des tableaux avec plus de trois dimensions. Ils peuvent rapidement devenir trop importants.

Initialisation
Vous pouvez initialiser lintgralit ou seulement une partie dun tableau, au moment de sa dclaration. Il faut prolonger la dclaration du tableau dun signe gal suivi dune liste entre accolades de valeurs spares par des virgules. Ces valeurs sont attribues dans lordre aux lments du tableau en commenant llment 0. Par exemple, linstruction suivante attribue la valeur 100 tableau[0], 200 tableau[1], 300 tableau[2] et 400 tableau[3]:
int tableau[4] = { 100, 200, 300, 400 };

Si vous nindiquez pas la taille du tableau, le compilateur va crer un tableau avec autant dlments que de valeurs initiales. Linstruction suivante est donc parfaitement quivalente la prcdente :
int tableau[] = { 100, 200, 300, 400 };

Si les lments dun tableau ne sont pas initialiss en dbut de programme, vous ne connaissez pas les valeurs qui y sont stockes quand le programme sexcute. Si vous initialisez plus dlments que le tableau nen contient, le compilateur envoie un message derreur.

Initialisation de tableaux plusieurs dimensions


Les tableaux plusieurs dimensions peuvent aussi tre initialiss. Les valeurs sont attribues squentiellement en incrmentant dabord le dernier index :
int tableau[4][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

http://fribok.blogspot.com/

Cette instruction affecte les valeurs dans lordre suivant :


tableau[0][0] tableau[0][1] tableau[0][2] tableau[1][0] tableau[1][1] tableau[1][2] etc. tableau[3][1] tableau[3][2] = = = = = = 1 2 3 4 5 6

= 11 = 12

Quand vous initialisez un tableau plusieurs dimensions, vous pouvez rendre le code source plus clair en groupant les valeurs entre des accolades supplmentaires, et en les rpartissant sur plusieurs lignes. Notre exemple prcdent pourrait tre rcrit de cette faon :
int tableau[4][3] = { { 1, 2, 3 } , { 4, 5, 6 } , { 7, 8, 9 } , { 10, 11, 12 } };

Il ne faut pas oublier la virgule qui doit sparer les valeurs, mme si elles sont dj spares par des accolades. Le Listing 8.3 cre un tableau trois dimensions de 1000 lments et y stocke des nombres de manire alatoire. Le programme afche ensuite le contenu des lments du tableau. Cest un bon exemple de lintrt quoffre un tableau. Imaginez le nombre de lignes de code qui auraient t ncessaires pour effectuer la mme tche avec des variables. Ce programme contient une nouvelle fonction de bibliothque : getch(). Cette fonction lit un caractre au clavier. Dans notre exemple, elle met le programme en pause jusqu ce que lutilisateur enfonce une touche du clavier. Cette fonction est dcrite en dtail au Chapitre 14. Listing 8.3 : Le programme alea.c cre un tableau plusieurs dimensions
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: /* alea.c -- Exemple dutilisation dun tableau plusieurs*/ /* dimensions */ #include <stdio.h> #include <stdlib.h> /* Dclaration dun tableau 3 dimensions de 1000 lments */ int random[10][10][10]; int a, b, c; int main() { /* On remplit le tableau avec des nombres alatoires. */ /* La fonction de bibliothque rand() renvoi un nombre */

http://fribok.blogspot.com/

14: /* alatoire. On utilise une boucle for pour chaque indice.*/ 15: 16: for (a = 0; a < 10; a++) 17:{ 18: for (b = 0; b < 10; b++) 19:{ 20: for (c = 0; c < 10; c++) 21: { 22: random[a][b][c] = rand(); 23: } 24: } 25:} 26: 27: /* On affiche les lments du Tableau10 par 10 */ 28: 29: for (a = 0; a < 10; a++) 30:{ 31: for (b = 0; b < 10; b++) 32:{ 33: for (c = 0; c < 10; c++) 34: { 35: printf("\nrandom[%d][%d][%d] = ", a, b, c); 36: printf("%d", random[a][b][c]); 37: } 38: printf("\nAppuyez sur Entre pour continuer, CTRL-C pour sortir."); 39: 40: getchar(); 41: } 42:} 43:exit(EXIT_SUCCESS); 44: }/* fin de la fonction main() */ random[0][0][0] = 346 random[0][0][1] = 130 random[0][0][2] = 10982 random[0][0][3] = 1090 random[0][0][4] = 11656 random[0][0][5] = 7117 random[0][0][6] = 17595 random[0][0][7] = 6415 random[0][0][8] = 22948 random[0][0][9] = 31126 Appuyez sur Entre pour continuer, ou CTRL-C pour sortir. random[0][1][0] = 346 random[0][1][1] = 130 random[0][1][2] = 10982 random[0][1][3] = 1090 random[0][1][4] = 11656 random[0][1][5] = 7117 random[0][1][6] = 17595 random[0][1][7] = 6415 random[0][1][8] = 22948

http://fribok.blogspot.com/

random[0][1][9] = 31126 Appuyez sur Entre pour continuer, ou CTRL-C pour sortir. etc. random[9][8][0] = 6287 random[9][8][1] = 26957 random[9][8][2] = 1530 random[9][8][3] = 14171 random[9][8][4] = 6957 random[9][8][5] = 213 random[9][8][6] = 14003 random[9][8][7] = 29736 random[9][8][8] = 15028 random[9][8][9] = 18968 Appuyez sur Entre pour continuer, ou CTRL-C pour sortir. random[9][9][0] = 28559 random[9][9][1] = 5268 random[9][9][2] = 10182 random[9][9][3] = 3633 random[9][9][4] = 24779 random[9][9][5] = 3024 random[9][9][6] = 10853 random[9][9][7] = 28205 random[9][9][8] = 8930 random[9][9][9] = 2873 Appuyez sur Entre pour continuer, ou CTRL-C pour sortir.

Analyse Au Chapitre 6, nous avons tudi un programme qui utilisait une boucle for imbrique. Celui-ci en a deux. Les lignes 7 et 8 contiennent les dnitions de 4 variables : random est un tableau trois dimensions qui stockera des nombres entiers alatoires et qui contient 1000 lments (10 10 10). La ligne 8 dclare les 3 variables a, b, et c destines au contrle des boucles. En ligne 4, ce programme inclut un chier en-tte dont nous navons que peu parl jusquici, stdlib.hstdlib.h (STanDart LIBrary). Il contient le prototype de la fonction rand() utilise la ligne 22. Cest galement lui qui dnit la constante EXIT_SUCCESS (ligne 43) et son pendant EXIT_FAILURE. Les deux instructions for imbriques reprsentent la partie principale du programme. La premire, aux lignes 16 25, a la mme structure que la deuxime aux lignes 29 42. La ligne 22 de la premire boucle sexcute de faon rptitive, et alimente le tableau random avec les nombres alatoires fournis par la fonction rand(). Si nous remontons un peu dans le listing, nous pouvons noter que la boucle for de la ligne 20 va sexcuter 10 fois pour des valeurs de la variable c allant de 0 9. Cette boucle reprsente lindex le plus droite du tableau random. La ligne 18 est la boucle de b, qui

http://fribok.blogspot.com/

reprsente lindex du milieu du tableau. Enn la ligne 16 incrmente la variable a pour lindex de gauche du tableau random. chaque changement de la valeur de a, la boucle contenant la variable b sexcute 10 fois et chaque excution de cette boucle, celle qui incrmente c a tourn aussi 10 fois. Ces boucles permettent donc dinitialiser tous les lments de random. Les lignes 29 42 contiennent la seconde srie de boucles for imbriques. Le principe est exactement le mme que pour les trois boucles prcdentes. Cette fois, leur tche consiste afcher, par groupe de 10, les valeurs prcdemment initialises. la n de chaque srie, les lignes 38 et 39 demandent lutilisateur sil veut continuer. La fonction getchar() suspend le programme jusqu ce que lon appuie sur Entre. Lancez ce programme et regardez les valeurs afches.

Taille maximale
La mmoire occupe par un tableau dpend du nombre et de la taille des lments quil contient. La taille dun lment dpend de la taille, sur votre ordinateur, du type de donne quil contient. Le Tableau 8.1 reprend les tailles qui avaient t attribues au Chapitre 3.
Tableau 8.1 : Espace mmoire ncessaire pour stocker les donnes numriques

Type de la donne stocke dans llment int short long float double

Taille de llment (en octets)


4 2 4 4 8

Lespace mmoire peut tre calcul lintrieur dun programme au moyen de loprateur sizeof().Cest un oprateur unaire, et non une fonction. Il prend le nom dune variable ou dun type de donne comme argument et en renvoie la taille en octets. Listing 8.4 : Utilisation de loprateur sizeof() pour calculer lespace occup par un tableau
1: 2: 3: 4: 5: 6: /* Exemple dutilisation de loprateur sizeof() */ #include <stdio.h> #include <stdlib.h> /* On dclare quelques tableaux de 100 lments */

http://fribok.blogspot.com/

Listing 8.4 : Utilisation de loprateur sizeof() pour calculer lespace occup par un tableau (suite)
7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: int inttab[100]; float floattab[100]; double doubletab[100]; int main() { /* On affiche la taille des types de donnes*/ printf("\n\nLa taille de int est de%d octets", sizeof(int)); printf("\nLa taille de short est de%d octets", sizeof(short)); printf("\nLa taille de long est de%d octets", sizeof(long)); printf("\nLa taille de float est de%d octets", sizeof(float)); printf("\nLa taille de double est de%d bytes", sizeof(double)); /* On affiche la taille des trois tableaux */ printf("\nTaille de inttab =%d octets", sizeof(inttab)); printf("\nTaille de floattab =%d octets", sizeof(floattab)); printf("\nTaille de doubletab =%d octets\n", sizeof(doubletab)); exit(EXIT_SUCCESS); }

La liste suivante correspond des programmes UNIX et Windows 32 bits :


La taille La taille La taille La taille La taille Taille de Taille de Taille de de int est de 4 octets de short est de 2 octets de long est de 4 octets de float est de 4 octets de double est de 8 octets inttab = 400 octets floattab = 400 octets doubletab = 800 octets

Analyse Saisissez et compilez ce programme en suivant la procdure du Chapitre 1. Son excution vous donnera la taille en octets des trois tableaux et des variables numriques. Les lignes 7, 8 et 9 dclarent trois tableaux qui contiendront des types de donnes diffrents. Leur taille respective est alors afche aux lignes 23 25. Elles sont calcules en multipliant la taille de la donne stocke dans le tableau par le nombre dlments du tableau. Excutez le programme et contrlez les rsultats. Comme vous avez pu le constater dans les rsultats prcdents, des machines ou des systmes dexploitation diffrents pourront travailler avec des types de donnes de taille diffrente.

http://fribok.blogspot.com/

Rsum
Les tableaux numriques fournissent une mthode puissante de stockage des donnes. Ils permettent de grouper des donnes de mme type sous un nom de groupe unique. Chaque donne, ou lment, est identie en utilisant un index entre crochets aprs le nom du tableau. Les tches de programmation qui impliquent un traitement rptitif des donnes conduisent naturellement lutilisation de tableaux. Avant dtre utilis, un tableau doit tre dclar. Il est possible dinitialiser quelques lments du tableau dans cette dclaration.

Q&R
Q Que se passera-t-il si jutilise une taille dindex suprieure au nombre dlments du tableau ? R Si lindex ne correspond pas la dclaration du tableau, le programme sera compil et pourra mme tourner. Les rsultats de cette excution sont imprvisibles et il pourrait tre trs difcile de retrouver la source des erreurs qui en dcouleront. Soyez donc trs prudent en initialisant et en stockant des donnes dans un tableau. Q Peut-on utiliser un tableau sans lavoir initialis ? R Cette erreur nest pas dtecte par le compilateur. Le tableau peut contenir nimporte quoi et le rsultat de son utilisation est imprvisible. En linitialisant, vous connaissez la valeur des donnes qui y sont stockes. Q Combien de dimensions un tableau peut-il avoir ? R La seule limite au nombre de dimensions est impose par la place mmoire. Les besoins en mmoire dun tableau augmentent considrablement avec le nombre de dimensions. Il faut viter de gaspiller la mmoire disponible en dclarant des tableaux ayant juste la taille ncessaire. Q Comment peut-on initialiser entirement et facilement un tableau ? R Vous pouvez le faire avec une instruction de dclaration comme celle que nous avons tudie dans ce chapitre, ou laide dune boucle for. Q Quel intrt y a-t-il utiliser un tableau plutt que des variables simples ? R Dans le cas du tableau, des donnes de mme type sont stockes sous un seul nom. Le programme du Listing 8.3 manipulait 1000 valeurs de donnes. La cration et linitialisation de 1000 variables diffrentes sont inconcevables, lusage dun tableau a considrablement simpli le travail.

http://fribok.blogspot.com/

Q Que faire lorsque lon ne peut pas prvoir la taille du tableau lors de lcriture du programme ? R Certaines fonctions en langage C permettent de rserver la mmoire ncessaire pour des variables ou des tableaux de faon dynamique. Ces fonctions seront traites au Chapitre 15.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

Quiz
1. Quels types de donnes peut-on stocker dans un tableau ? 2. Quelle est la valeur dindex du premier des dix lments dun tableau ? 3. Quelle est la dernire valeur dindex dun tableau une dimension qui contient n lments ? 4. Que se passe-t-il si un programme essaye daccder un lment de tableau avec un index invalide ? 5. Comment faut-il dclarer un tableau plusieurs dimensions ? 6. Quelle est la taille du tableau suivant ?
int tableau[2][3][5][8];

7. Comment sappelle le dixime lment du tableau de la question 6 ?

Exercices
1. crivez une ligne de code dclarant trois tableaux une dimension pour stocker des entiers qui sappelleraient un, deux, et trois avec 1000 lments chacun. 2. crivez la dclaration dun tableau de 10 lments initialiss 1 pour stocker des entiers. 3. crivez le code ncessaire linitialisation des lments du tableau suivant avec la valeur 88 :
int huitethuit[88];

http://fribok.blogspot.com/

4. crivez le code ncessaire linitialisation des lments du tableau suivant avec la valeur 0 :
int stuff[12][10];

5. CHERCHEZ LERREUR :
int x, y; int tableau[10][3]; int main() { for (x = 0; x < 3; x++) for (y = 0; y < 10; y++) tableau[x][y] = 0; exit(EXIT_SUCCESS); }

6. CHERCHEZ LERREUR :
int tableau[10]; int x = 1; int main() { for (x = 1; x <= 10; x++) tableau[x] = 99; exit(EXIT_SUCCESS); }

7. crivez un programme qui stocke des nombres alatoires dans un tableau deux dimensions de 5 par 4. Afchez lcran la valeur des lments du tableau en colonnes (utilisez la fonction rand() du Listing 8.3). 8. Modiez le Listing 8.3 pour utiliser un tableau une dimension. Calculez et afchez la moyenne des 1000 valeurs avant de les afcher individuellement. Noubliez pas de mettre le programme en pause aprs lafchage dun groupe de 10 valeurs. 9. crivez un programme qui initialise un tableau de 10 lments. Chaque lment devra avoir la valeur de son index. Lexcution du programme se terminera en afchant le contenu des 10 lments. 10. Modiez le programme de lexercice 9 pour quil copie ensuite ses lments dans un nouveau tableau en ajoutant 10 chacune des valeurs. Afchez la valeur des lments du second tableau.

http://fribok.blogspot.com/

9
Les pointeurs
Les pointeurs jouent un rle trs important dans le langage C. Ils permettent de manipuler les donnes dans vos programmes. Aujourdhui, vous allez tudier :

La dnition dun pointeur Lutilisation des pointeurs La dclaration et linitialisation des pointeurs Lutilisation des pointeurs avec des variables simples et des tableaux Le passage des tableaux une fonction avec les pointeurs

Lutilisation de pointeurs offre de nombreux avantages qui peuvent tre partags en deux catgories : celle des tches qui sont excutes de manire plus simple avec des pointeurs, et celle des tches qui ne pourraient pas tre ralises sans pointeurs. Pour devenir un bon programmeur en langage C, il est impratif de bien comprendre les principes de fonctionnement des pointeurs.

http://fribok.blogspot.com/

Dnition
Pour comprendre ce que sont les pointeurs, vous devez avoir une ide de la faon dont votre ordinateur stocke les informations en mmoire.

La mmoire de votre ordinateur


La mmoire vive de votre PC est constitue de millions demplacements mmoire rangs de faon squentielle. Chaque emplacement a une adresse unique, comprise entre 0 et une valeur maximale qui dpend de la quantit de mmoire installe sur votre machine. Quand votre ordinateur fonctionne, une partie de sa mmoire vive est occupe par le systme dexploitation. Si vous lancez un programme, le code (les instructions en langage machine) et les donnes quil utilise occuperont en partie cette mmoire. Nous allons tudier de quelle faon votre programme occupera cette mmoire. Quand un programme dclare une variable, le compilateur rserve un emplacement mmoire avec une adresse unique pour stocker cette variable. Il associe ladresse au nom de la variable. Quand le programme utilise le nom de la variable, il accde automatiquement lemplacement mmoire correspondant. Ce mcanisme est transparent pour lutilisateur du programme, qui utilise le nom de la variable sans se soucier de lendroit o lordinateur la stocke. Cela est illustr par le schma de la Figure 9.1.
Figure 9.1 Une variable de programme a une adresse de mmoire spcique.
1000 1001 1002 1003 1004 100
rate

1005

Une variable appele rate est dclare et initialise 100. Le compilateur a rserv un emplacement mmoire ladresse 1004, quil associe donc au nom de la variable.

Cration dun pointeur


Vous pouvez remarquer que ladresse de la variable rate est un nombre, et quelle peut donc tre utilise comme nimporte quel autre nombre en langage C. Si vous connaissez ladresse dune variable, vous pouvez crer une autre variable pour y stocker ladresse de la premire. Dans notre exemple, la premire tape consiste dclarer la variable dans laquelle on stockera ladresse de rate. Nous allons lappeler p rate. Le schma suivant

http://fribok.blogspot.com/

montre quun emplacement a bien t rserv pour p rate, mais la valeur qui y est stocke est inconnue.
Figure 9.2 Un emplacement a t allou la variable p_rate.
1000 ?
p_rate

1001

1002

1003

1004 100
rate

1005

Ltape suivante consiste stocker ladresse de rate dans la variable p rate. Celle-ci reprsente maintenant lemplacement mmoire de la variable rate: en langage C, p rate pointe sur rate, ou p rate est un pointeur vers rate.
Figure 9.3 La variable p_rate contient ladresse de la variable rate, elle est galement un pointeur vers rate.
1000 1004 1001 1002 1003 1004 100 1005

p_rate

rate

En rsum, un pointeur est une variable qui contient ladresse dune autre variable. tudions maintenant lutilisation de ces pointeurs dans un programme C.

Pointeurs et variables simples


Lexemple prcdent montrait une variable pointant sur une autre variable simple (ce nest pas un tableau). Voyons maintenant comment crer et utiliser ce type de pointeur.

Dclaration
Un pointeur est une variable numrique qui doit tre dclare, comme toutes les variables, avant dtre utilise. Le nom des pointeurs suit les mmes rgles que celui des autres variables et doit tre unique. Nous utilisons, dans ce chapitre, une convention pour le nom des pointeurs. Si le nom de la variable est nom, le pointeur sappellera p nom. Ce nest pas une rgle, vous pouvez choisir votre propre convention. La dclaration dun pointeur a la forme suivante :
nomtype *nomptr;

nomtype reprsente le type de la variable pointe. Lastrisque (*) est loprateur indirect, il indique que nomptr est un pointeur vers une variable de type nomtype, et non une variable

http://fribok.blogspot.com/

de type nomtype. Une dclaration peut contenir des pointeurs et des variables. Voici quelques exemples :
char *ch1, *ch2;/* ch1 et ch2 pointent sur une variable */ /* de type char */ float *valeur, pourcent;/* valeur est un pointeur vers une */ /* variable de type float et pourcent */ /* est une variable de type float */

Info

Le symbole * reprsente loprateur indirect et loprateur de multiplication. Le compilateur fera la diffrence en fonction du contexte.

Initialisation
Dclarer un pointeur nest pas sufsant ; si vous ne le faites pas pointer sur une variable, il est inutile. Pour les mmes raisons quavec des variables, travailler avec un pointeur qui na pas t initialis peut se rvler dsastreux. Un pointeur doit contenir ladresse dune variable, et cest le programme qui doit sen charger en utilisant loprateur dadresse (&). Quand il est plac avant le nom de la variable, loprateur dadresse renvoie ladresse de cette variable. Linitialisation dun pointeur est donc une instruction de la forme :
pointeur = &variable;

Si nous reprenons lexemple de la Figure 9.3, linstruction correspondante aurait t :


p_rate = &rate; /* on attribue ladresse de rate p_rate */

Avant cette instruction, p rate ne pointait vers rien de particulier. Aprs, p rate devient un pointeur vers rate.

Pointeurs, mode demploi


Maintenant que vous savez dclarer et initialiser un pointeur, vous devez apprendre lutiliser. Loprateur indirect (*) entre de nouveau en jeu. Quand cet oprateur prcde le nom dun pointeur, il fait rfrence la variable qui est pointe. Reprenons notre pointeur p rate initialis pour pointer vers la variable rate. *p rate reprsente la variable rate. Pour afcher la valeur de la variable, vous pouvez crire :
printf("%d", rate),

http://fribok.blogspot.com/

ou bien
printf("%d", *p_rate);

En langage C, ces deux instructions sont quivalentes. Si vous accdez au contenu de la variable en utilisant son nom, vous effectuez un accs direct. Si vous accdez au contenu dune variable par lintermdiaire de son pointeur, vous effectuez un accs indirect ou une indirection. La Figure 9.4 montre que le nom dun pointeur prcd dun oprateur dindirection se rfre la valeur pointe.
Figure 9.4 Loprateur dindirection associ un pointeur.
1000 1004
p_rate

1001

1002

1003

1004 100

1005

rate *p_rate

Les pointeurs sont trs importants en langage C, il est essentiel de bien comprendre leur fonctionnement. Si votre pointeur sappelle ptr et quil a t initialis pour pointer sur la variable var alors :

*ptr et var reprsentent le contenu de var. ptr et &var reprsentent ladresse de var.

Listing 9.1 : Utilisation des pointeurs


1: /* Exemple simple dutilisation dun pointeur. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: /* Dclaration et initialisation dune variable int */ 6: 7: int var = 1; 8: 9: /* Dclaration dun pointeur vers une variable int */ 10: 11: int *ptr; 12: 13: int main() 14: { 15: /* Initialisation de ptr*/ 16: 17: ptr = &var; 18: 19: /* Accs direct et indirect var */ 20:

http://fribok.blogspot.com/

Listing 9.1 : Utilisation des pointeurs (suite)


21: 22: 23: 24: 25: 26: 27: 28: 29: 30: printf("Accs direct, var =%d\n", var); printf("Accs indirect, var =%d\n\n", *ptr); /* Affichage de ladresse avec les deux mthodes */ printf("Ladresse de var =%d\n", &var); printf("Ladresse de var =%d\n", ptr); exit(EXIT_FAILURE); }

Accs direct, var = 1 Accs indirect, var = 1 Ladresse de var = 4264228 Ladresse de var = 4264228

ntion Atte

Sur votre ordinateur, ladresse de la variable var sera certainement diffrente de 4264228.

Analyse Ce programme utilise deux variables. La ligne 7 dclare la variable var de type int et linitialise 1. La ligne 11 contient la dclaration du pointeur ptr vers une variable de type int. La ligne 17 attribue ladresse de var au pointeur avec loprateur dadresse (&). Le programme afche ensuite la valeur de ces deux variables lcran. La ligne 21 afche la valeur de var, et la ligne 22 afche la valeur stocke ladresse sur laquelle ptr pointe. Dans notre exemple, cette valeur est 1. La ligne 26 afche ladresse de var en utilisant loprateur dadresse. La ligne 27 afche la mme adresse en utilisant le pointeur ptr. Ce programme illustre bien les relations qui existent entre une variable, son adresse, un pointeur et la rfrence la variable pointe.
eils Cons

faire Veillez bien comprendre ce que reprsente un pointeur et comment il travaille. Le langage C et les pointeurs vont de pair. ne pas faire Nutilisez pas un pointeur qui na pas t initialis. Les rsultats pourraient tre dsastreux.

http://fribok.blogspot.com/

Pointeurs et types de variables


Les diffrents types de variables du langage C noccupent pas tous la mme mmoire. Sur la plupart des systmes, une variable int prend quatre octets, une variable double en prend huit, etc. Chaque octet en mmoire possde sa propre adresse ; une variable qui occupe plusieurs octets occupe donc plusieurs adresses. Ladresse dune donne est en fait ladresse du premier octet occup. Voici un exemple qui dclare et initialise trois variables :
int vint = 12252; char vchar = 90; double vdouble = 1200.156004;

Ces variables sont stockes en mmoire comme le montre la Figure 9.5. La variable int occupe quatre octets, la variable char en occupe un, et la variable double huit. Voici la dclaration et linitialisation des pointeurs vers ces trois variables :
int *p_vint; char *p_vchar; double *p_vdouble; /* des instructions peuvent tre insres ici */ p_vint = &vint; p_vchar = &vchar; p_vdouble = &vdouble;

Chaque pointeur contient ladresse du premier octet de la variable pointe. Ainsi, p vint est gal 1000, p vchar a la valeur 1005 et p vdouble est gal 1008. Le compilateur sait quun pointeur vers une variable de type int pointe sur le premier des quatre octets, quun pointeur de variable de type double pointe sur le premier des huit octets, etc. Les Figures 9.5 et 9.6 reprsentent les trois variables de lexemple, spares par des emplacements vides. Leur seul intrt est de rendre la gure plus lisible ; dans la ralit, le compilateur aurait stock les trois variables dans des emplacements mmoire adjacents.
vint vchar vdouble

{
vchar

{ {
vfloat

Figure 9.5 Les diffrents types de variables noccupent pas tous la mme quantit de mmoire.
vint

Figure 9.6 Le compilateur "connat" la taille des variables vers lesquelles pointe un pointeur.

{ {

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 12592 90 1200.156004

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 12592 90 1200.156004 p_vint p_vchar p_vfloat (4 octets commenant (1 octet commenant (8 octets commenant l'adresse 1000) l'adresse 1005) l'adresse 1008)

http://fribok.blogspot.com/

Pointeurs et tableaux
Les pointeurs sont trs utiles pour travailler avec les variables, mais ils le sont encore plus quand on les utilise avec les tableaux. En fait, les index de tableaux dont on a parl au Chapitre 8 ne sont rien dautre que des pointeurs.

Noms de tableau et pointeurs


Un nom de tableau sans les crochets sutilise la plupart du temps comme un pointeur vers le premier lment du tableau. Si vous avez dclar le tableau data[], data aura la valeur de ladresse de data[0] et sera donc quivalent lexpression &data[0].
ntion Atte

Le nom du tableau nest pas un pointeur mme sil est souvent utilis comme tel. Par exemple, contrairement un pointeur, il nest pas possible de modier la valeur dun tableau. Un autre exemple est la valeur de sizeof() qui, pour un pointeur, renvoie toujours la mme valeur (mme sil pointe sur un tableau) alors que pour un tableau, il renvoie une valeur qui dpend de la taille du tableau.

Vous pouvez quand mme dclarer un pointeur variable et linitialiser pour pointer sur le premier lment du tableau :
int tableau[100], *p_tableau; /* instructions */ p_tableau = tableau;

p tableau tant un pointeur variable, il peut tre modi pour pointer ailleurs. Contrairement tableau, p tableau ne pointe pas obligatoirement sur le premier lment de tableau[]. Il pourrait, par exemple, pointer vers dautres lments du tableau. Mais avant cela, il faut savoir comment sont stocks en mmoire les lments dun tableau.

Stockage des lments dun tableau


Les lments dun tableau sont stocks dans des emplacements mmoire squentiels, le premier lment ayant ladresse la plus basse. Ladresse dun autre lment, par rapport au premier, dpend de la taille des valeurs stockes dans le tableau et de lindex de cet lment. Prenons comme exemple un tableau de type int. Une variable int occupe quatre octets en mmoire. Chaque lment du tableau sera donc situ quatre octets plus loin que le prcdent, et

http://fribok.blogspot.com/

son adresse sera gale celle de llment prcdent plus quatre. Avec des variables de type double (8 octets), chaque lment serait stock dans huit octets adjacents ; la diffrence entre les adresses de deux lments voisins serait alors de huit. La Figure 9.7 illustre les relations existant entre le stockage du tableau et les adresses, pour un tableau de type int avec six lments, et pour un tableau de type double avec trois lments.
int x[6]; 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 x[4] x[0] x[1] x[2] x[3] x[5]

double expenses[3]; 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 expenses[0] expenses[2] expenses[1]

Figure 9.7 Stockage de tableaux contenant diffrents types de donnes.

En tudiant la Figure 9.7, vous comprendrez pourquoi les expressions suivantes sont vraies :
1: 2: 3: 4: 5: 6: x == 1000 &x[0] == 1000 &x[1] == 1004 expenses == 1250 &expenses[0] == 1250 &expenses[1] == 1258

x exprim sans crochets est ladresse du premier lment (x[0]). La gure nous montre que x[0] se situe ladresse 1000, ce qui justie aussi la ligne 2. La ligne 3 indique que ladresse du second lment (index 1) est 1004. Il est facile de le vrier sur la gure. Les lignes 4, 5, et 6 sont quivalentes aux lignes 1, 2, et 3 respectivement. La diffrence tient aux adresses qui vont de quatre en quatre dans le cas des donnes int, et de huit en huit pour les donnes de type double. Vous pouvez constater, partir de ces exemples, quun pointeur devra tre incrment de quatre pour accder des lments successifs dun tableau de type int, et de huit dans le cas dun tableau de type double. Pour accder des lments successifs dun tableau contenant un type de donne particulier, le pointeur devra tre incrment de la valeur sizeof(typedonne). Loprateur sizeof renvoie la taille en octets du type de donne reu en argument. Mieux, sil sagit bien dun pointeur et non dun tableau, incrmentez-le de la valeur de sizeof(ptr) o ptr est le nom de votre pointeur.

http://fribok.blogspot.com/

Listing 9.2 : Afchage des adresses dlments successifs dun tableau


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: /* Ce programme vous montre la relation existant entre les */ /* adresses et les lments de tableaux contenant diffrents */ /* types de donnes. */ #include <stdio.h> #include <stdlib.h> /* Dclaration de trois tableaux et dune variable compteur. */ short sh[10], x; int i[10]; double d[10]; int main() { /* Affichage de len-tte du tableau */ printf("\t\tShort\t\tEntier\t\tDouble"); printf("\n================================"); printf("======================"); /* Affichage de ladresse de chaque lment du tableau. */ for (x = 0; x < 10; x++) printf("\nElement%d:\t%ld\t\t%ld\t\t%ld", x, &sh[x],&i[x], &d[x]); printf("\n================================"); printf("======================\n"); exit(EXIT_SUCCESS); }

ShortEntierDouble ================================================ Element 0:139214141454 Element 1:139414181462 Element 2:139614221470 Element 3:139814261478 Element 4:140014301486 Element 5:140214341494 Element 6:140414381502 Element 7:140614421510 Element 8:140814461518 Element 9:141014501526 ================================================

Sur votre systme, les adresses seront diffrentes, mais la diffrence entre deux adresses sera identique. Il y a deux octets entre deux lments de type short, quatre octets entre chaque lment de type int et 8 octets entre deux lments double.

http://fribok.blogspot.com/

Analyse Ce programme utilise le caractre (\) que nous avons tudi au Chapitre 7 pour mettre en forme le tableau qui sera afch. La fonction printf(), appele en lignes 16 et 24, utilise (\t) pour aligner les colonnes du tableau. Les trois tableaux du programme sont dclars aux lignes 8, 9 et 10. Le tableau sh est de type short, i est de type int et d de type double. La ligne 16 afche len-tte des colonnes et les lignes 18, 19, 27 et 28 des signes (=) pour sparer les rsultats. La boucle for, en lignes 23, 24 et 25, afche chaque ligne de rsultats.

Pointeur arithmtique
Nous venons de voir que le pointeur du premier lment dun tableau doit tre incrment dun nombre doctets gal la taille des donnes du tableau pour pointer sur llment suivant. Pour pointer sur un lment quelconque en utilisant une notation de type pointeur, on utilise le pointeur arithmtique.

Incrmenter les pointeurs


Incrmenter un pointeur consiste en augmenter la valeur. Si vous incrmentez un pointeur de 1, le pointeur arithmtique va augmenter sa valeur pour quil accde llment de tableau suivant. En fait, C connat le type de donne du tableau partir de la dclaration, et il va incrmenter le pointeur de la taille de cette donne chaque fois. Par exemple, si ptr int pointe sur un lment de tableau de type int, linstruction suivante :
ptr_int++;

incrmente la valeur de ce pointeur de 4 pour quil pointe sur llment int suivant. De la mme faon, si vous augmentez la valeur du pointeur de n, C va incrmenter ce pointeur pour quil pointe sur le n-ime lment suivant :
ptr_int += 2;

Cette instruction va augmenter de 8 la valeur du pointeur, pour quil pointe 2 lments plus loin.

Dcrmenter les pointeurs


La dcrmentation des pointeurs suit le mme principe que lincrmentation. Si vous utilisez les oprateurs () ou (=) pour dcrmenter un pointeur, le pointeur arithmtique va diminuer sa valeur automatiquement en fonction de la taille des donnes pointes.

http://fribok.blogspot.com/

Le Listing 9.3 prsente un exemple dutilisation du pointeur arithmtique pour accder aux lments dun tableau. Lincrmentation du pointeur permet au programme de se dplacer facilement dans le tableau. Listing 9.3 : Utilisation dun pointeur arithmtique pour accder aux lments dun tableau
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: /* Utilisation dun pointeur arithmtique pour accder */ /* aux lments dun tableau. */ #include <stdio.h> #include <stdlib.h> #define MAX 10 /* Dclaration et initialisation dun tableau dentiers. */ int i_tableau[MAX] = { 0,1,2,3,4,5,6,7,8,9 }; /* Dclaration dun pointeur vers int et dune variable int. */ int *i_ptr, count; /* Dclaration et initialisation dun tableau de type double. */ double d_tableau[MAX] = {.0, .1, .2, .3, .4, .5, .6, .7, .8, .9}; /* Dclaration dun pointeur vers double. */ double *d_ptr; int main() { /* Initialisation des pointeurs. */ i_ptr = i_tableau; d_ptr = d_tableau; /* Affichage des lments du tableau. */ for (count = 0; count < MAX; count++) printf("%d\t%f\n", *i_ptr++, *d_ptr++); exit(EXIT_SUCCESS); }

00.000000 10.100000 20.200000 30.300000 40.400000 50.500000

http://fribok.blogspot.com/

60.600000 70.700000 80.800000 90.900000

Analyse La ligne 5 dnie et initialise 10 la constante MAX qui sera utilise tout au long de ce programme. En ligne 9, MAX indique le nombre dentiers stocks dans i tableau. La ligne 13 dclare un pointeur appel i ptr et une variable simple count de type int. Un second tableau, de type double, est dni et initialis en ligne 17. Ce tableau contient aussi MAX lments. La ligne 21 dclare le pointeur d ptr vers les donnes double. La fonction main() commence en ligne 23 et nit en ligne 36. Le programme attribue ladresse de dbut des deux tableaux leur pointeur respectif en lignes 27 et 28. Linstruction for, en lignes 32 et 33, utilise la variable count pour sexcuter MAX fois. chaque excution, la ligne 33 afche le contenu des lments points, avec la fonction printf(), puis incrmente les deux pointeurs pour accder aux deux lments de tableau suivants. Lutilisation de pointeurs arithmtiques dans le Listing 9.3 noffre pas davantages particuliers. Lutilisation de lindex aurait t plus simple. Quand vous commencerez crire des programmes plus complexes, vous trouverez trs vite lemploi de ce type de pointeur avantageux. Souvenez-vous quil nest pas possible dincrmenter ou de dcrmenter un pointeur constant (un nom de tableau sans les crochets). Souvenez-vous aussi que lorsque vous vous dplacez dans un tableau laide dun pointeur, le compilateur C ne garde pas de trace du dbut et de la n du tableau. Les donnes qui sont stockes avant ou aprs le tableau ne sont pas des lments ; soyez donc trs prudent et contrlez lemplacement des donnes pointes.

Autre utilisation des pointeurs


La dernire opration que lon peut effectuer avec des pointeurs est la diffrence entre deux pointeurs. Si vous avez deux pointeurs sur un mme tableau, le rsultat de leur soustraction correspond au nombre dlments les sparant. Exemple :
ptr1 ptr2

Cette instruction donne le nombre dlments qui sparent les deux lments points par ptr1 et ptr2. Les oprateurs de comparaison ==, !=, >, <, >= et <= peuvent aussi tre

http://fribok.blogspot.com/

utiliss. Les premiers lments dun tableau ont toujours une adresse plus basse que les derniers. Ainsi, si ptr1 et ptr2 sont deux pointeurs dun mme tableau, la comparaison :
ptr1 < ptr2

est vraie si ptr1 pointe sur un lment dindex plus petit que ptr2. Beaucoup doprations arithmtiques sont rserves aux variables simples, car elles nauraient aucun sens avec les pointeurs. Par exemple, si ptr est un pointeur, linstruction :
ptr *= 2;

gnrera un message derreur. Le Tableau 9.1 vous donne la liste des six oprations possibles avec les pointeurs.
Tableau 9.1 : Oprations sur les pointeurs

Oprateur
Affectation Indirection Adresse de Incrment Dcrment Diffrence Comparaison

Description
Vous pouvez attribuer une valeur un pointeur. Cette valeur doit correspondre une adresse obtenue avec loprateur dadresse (&,), ou partir dun pointeur constant. Loprateur indirect (*) donne la valeur stocke lemplacement point. Vous pouvez utiliser loprateur dadresse pour trouver ladresse dun pointeur et obtenir un pointeur vers un pointeur. On peut ajouter un nombre entier la valeur dun pointeur pour pointer sur un emplacement mmoire diffrent. On peut soustraire un entier la valeur dun pointeur pour pointer sur un emplacement mmoire diffrent. Vous pouvez soustraire un entier de la valeur dun pointeur pour pointer sur un emplacement mmoire diffrent. Ces oprateurs ne sont valides que pour deux pointeurs dun mme tableau.

Prcautions demploi
Quand vous utilisez des pointeurs dans un programme, une grosse erreur est viter : utiliser un pointeur non initialis gauche dune instruction daffectation. Par exemple, dans la dclaration suivante :
int *ptr;

le pointeur nest pas initialis. Cela signie quil ne pointe pas sur un emplacement connu. Si vous crivez :
*ptr =12;

http://fribok.blogspot.com/

la valeur 12 va tre stocke ladresse (inconnue) pointe par ptr. Cette adresse peut se situer nimporte o en mmoire, au milieu du code du systme dexploitation par exemple. La valeur 12 risque dcraser une donne importante, et le rsultat peut aller de simples erreurs dans un programme larrt complet du systme.
eils Cons

ne pas faire Effectuer des oprations mathmatiques comme des divisions, des multiplications ou des modulos avec des pointeurs. Les seules oprations possibles sont lincrmentation ou le calcul de la diffrence entre deux pointeurs dun mme tableau. Noubliez pas que lajout ou la soustraction dun entier un pointeur change la valeur de ce pointeur en fonction de la taille des donnes sur lesquelles il pointe. Incrmenter ou dcrmenter une variable de tableau. Initialisez un pointeur avec ladresse de dbut du tableau et incrmentez-le. faire Renseignez-vous sur la taille des diffrents types de donnes dans votre ordinateur.

Pointeurs et index de tableaux


Un nom de tableau sans les crochets est un pointeur vers le premier lment du tableau. Par consquent, vous pouvez accder au premier lment de ce tableau avec loprateur indirect (*). Si tab[] est un tableau, lexpression *tab reprsente le premier lment de ce tableau, *(tab+1) est le deuxime lment, etc. En gnralisant, nous obtenons les relations suivantes :
*(tab) == tab[0] *(tab+1) == tab[1] *(tab+2) == tab[2] etc. *(tab+n) == tab[n]

Ces expressions vous donnent les quivalences entre la notation de lindex et celle utilisant les pointeurs. Le compilateur C ne fait aucune diffrence entre ces deux mthodes daccs aux donnes dun tableau.

http://fribok.blogspot.com/

Passer des tableaux une fonction


Pointeurs et tableaux sont troitement lis en langage C, et cette relation va permettre le passage dun tableau comme argument dune fonction. Comme nous lavons appris au Chapitre 5, un argument est une valeur passe une fonction par le programme appelant. Ce doit tre une valeur numrique de type int, float ou autre. Un lment de tableau peut tre transmis une fonction, mais pas un tableau tout entier. Un pointeur tant une valeur numrique (adresse), vous pouvez passer cette valeur une fonction. La fonction connaissant ladresse du tableau, elle pourra accder tous ses lments en utilisant un pointeur. Si vous passez un tableau en argument une fonction, un problme va se poser. Si la fonction doit accder diffrents lments (par exemple, trouver llment ayant la plus grande valeur) de ce tableau, elle doit en connatre le nombre. Il y a deux mthodes pour faire connatre la taille du tableau la fonction. Vous pouvez identier le dernier lment dun tableau en y stockant une valeur particulire. Quand la fonction accdera aux lments du tableau elle reconnatra le dernier par cette valeur. Linconvnient de cette mthode est que vous devez rserver une valeur pour lindicateur de n de tableau. Vous ntes plus libre de stocker toutes les valeurs possibles dans votre tableau. Lautre mthode est plus directe. On passe la taille du tableau en argument. La fonction en reoit donc deux, le pointeur sur le premier lment et un nombre entier indiquant le nombre dlments du tableau. Cest celle que nous avons choisie dans ce livre. Ce nest pas forcment la meilleure : cela dpend des cas. Le Listing 9.4 prsente un programme qui lit une srie de valeurs entres par lutilisateur et la stocke dans un tableau. Il appelle ensuite la fonction largest() en lui passant le tableau (pointeur et taille). La fonction cherche la plus grande valeur stocke dans le tableau et la renvoie au programme. Listing 9.4 : Exemple de passage dun tableau une fonction
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: /* Comment passer dun tableau une fonction. */ #include <stdio.h> #include <stdlib.h> #define MAX 10 int tab[MAX], count; int largest(int x[], int y); int main()

http://fribok.blogspot.com/

12: { 13: /* Lecture des MAX valeurs partir du clavier. */ 14: 15: for (count = 0; count < MAX; count++) 16: { 17: printf("Entrez une valeur entire: "); 18: scanf("%d", &tab[count]); 19: } 20: 21: /* Appel de la fonction et affichage de la valeur renvoye. */ 22: 23: printf("\n\nLa valeur la plus grande est%d\n", largest(tab, MAX)); 24: exit(EXIT_SUCCESS); 25: } 26: 27: /* La fonction largest() renvoie la valeur la plus grande */ 28: /* dun tableau dentiers. */ 29: 30: int largest(int x[], int y) 31: { 32: int count, biggest = x[0]; 33: 34: for (count = 1; count < y; count++) 35: { 36: if (x[count] > biggest) 37: biggest = x[count]; 38: } 39: 40: return biggest; 41: } Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez une une une une une une une une une une valeur valeur valeur valeur valeur valeur valeur valeur valeur valeur entire: entire: entire: entire: entire: entire: entire: entire: entire: entire: 1 2 3 4 5 10 9 8 7 6

La valeur la plus grande est 10

Analyse Les lignes 9 et 30 contiennent le prototype et len-tte de la fonction largest(). Le premier argument pass, int x[], est un pointeur de type int. Le deuxime, y, est un entier. La dclaration de cette fonction aurait pu scrire :
int largest(int *x, int y);

http://fribok.blogspot.com/

Les deux formes sont quivalentes : int x[] et int *x signient "pointeur vers une donne entire". Au moment de lappel de la fonction largest(), x contient la valeur du premier argument, cest donc un pointeur vers le premier lment du tableau. Vous pouvez utiliser x partout o un pointeur peut tre utilis. Dans cette fonction, on accde aux lments du tableau au moyen de lindex (lignes 36 et 37). La notation "pointeur" aurait pu tre utilise de cette faon :
for (count = 0; count < y; count++) { if (*(x+count) > biggest) biggest = *(x+count); }

Le Listing 9.5 prsente une autre mthode pour passer dun tableau une fonction. Listing 9.5 : Une autre mthode pour passer dun tableau une fonction
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: /* Comment transmettre un tableau une fonction. Autre mthode. #include <stdio.h> #include <stdlib.h> #define MAX 10 int tab[MAX+1], count; int largest(int x[]); int main() { /* Lecture des MAX valeurs partir du clavier. */ for (count = 0; count < MAX; count++) { printf("Entrez une valeur entire: scanf("%d", &tab[count]); */

");

if (tab[count] == 0) count = MAX;/* sortie de la boucle */ } tab[MAX] = 0; /* Appel de la fonction et affichage de la valeur renvoye. */ printf("\n\nLa valeur la plus grande est%d\n", largest(tab)); exit(EXIT_SUCCESS); } /* La fonction largest() renvoie la plus grande valeur du tableau. */

http://fribok.blogspot.com/

32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:

int largest(int x[]) { int count, biggest = x[0]; for (count = 1; x[count]!= 0; count++) { if (x[count] > biggest) biggest = x[count]; } return biggest; } une une une une une une une une une une valeur valeur valeur valeur valeur valeur valeur valeur valeur valeur entire: entire: entire: entire: entire: entire: entire: entire: entire: entire: 1 2 3 4 5 10 9 8 7 6

Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez Entrez

La valeur la plus grande est 10

Voici le rsultat obtenu aprs avoir droul le mme programme une seconde fois :
Entrez Entrez Entrez Entrez Entrez Entrez une une une une une une valeur valeur valeur valeur valeur valeur entire: entire: entire: entire: entire: entire: 10 20 55 3 12 0

La valeur la plus grande est 55

Analyse La fonction largest() de ce programme a le mme rle que celle du code source prcdent, mais on ne lui passe que le pointeur. La boucle for de la ligne 37 recherche la valeur la plus grande jusqu ce quelle trouve la valeur 0. Cette valeur, qui provoque la sortie de la boucle, correspond la n du tableau. Le Listing 9.5 prsente quelques diffrences par rapport au Listing 9.4. La ligne 7, par exemple, ajoute au tableau un lment qui servira dindicateur de n. En lignes 20 et 21, une instruction if supplmentaire vrie les donnes entres par lutilisateur, la valeur 0 entranant la n de la lecture des donnes. Si lutilisateur tape 0, La valeur maximum est

http://fribok.blogspot.com/

stocke dans la variable count pour que la sortie de la boucle for se fasse normalement. La ligne 23 initialise le dernier lment 0. En ajoutant quelques commandes la lecture des donnes, la fonction largest() pourrait travailler avec des tableaux de nimporte quelle taille. Il ne faudra pas oublier de mettre un 0 dans le dernier lment, sinon la fonction continuera lire les donnes en mmoire audel du tableau jusqu ce quelle trouve une valeur 0. Le passage dun tableau en argument une fonction nest pas particulirement compliqu. Il suft de transmettre le pointeur du premier lment et, la plupart du temps, le nombre dlments du tableau. La fonction pourra ensuite accder aux diffrents lments en utilisant la notation index ou pointeur.
ntion Atte

Quand une variable simple est passe une fonction, cest une copie de la valeur de cette variable qui est transmise (voir Chapitre 5). La fonction peut utiliser cette valeur, mais elle ne peut pas la changer, car elle na pas accs la variable. Transmettre un tableau une fonction est un problme diffrent. La fonction pointe directement sur les lments du tableau (ce ne sont pas des copies) parce quelle en connat ladresse. Cette fonction peut donc modier les valeurs stockes dans le tableau.

Rsum
Les pointeurs constituent un lment important de la programmation en langage C. Un pointeur est une variable qui contient ladresse dune autre variable : il "pointe" sur cette variable. Les deux oprateurs lis aux pointeurs sont loprateur dadresse (&) et loprateur indirect (*). Loprateur dadresse renvoie ladresse de la variable devant laquelle il est plac (ex &var). Loprateur indirect renvoie ladresse de la variable pointe par le pointeur devant lequel il est plac (ex *ptr). Les tableaux et les pointeurs sont aussi lis. Un nom de tableau sans crochets peut tre assimil un pointeur sur le premier lment du tableau. Les pointeurs arithmtiques permettent daccder facilement aux lments dun tableau en utilisant la notation pointeur. La notation index est, en fait, une forme de notation pointeur. Un tableau peut tre pass en argument une fonction par lintermdiaire de son pointeur. Quand la fonction connat ladresse et la taille du tableau, elle peut accder librement aux lments de ce tableau en utilisant la mthode index ou la mthode pointeur.

http://fribok.blogspot.com/

Q&R
Q Pourquoi les pointeurs sont-ils importants en langage C ? R Les pointeurs vous aident contrler le programme et les donnes. Utiliss avec les fonctions, ils permettent de changer la valeur des donnes transmises en argument. Le Chapitre 15 vous donnera dautres exemples dapplications pour les pointeurs. Q Comment le compilateur sait-il si loprateur (*) est utilis pour un calcul de multiplication, une indirection ou une dclaration de pointeur ? R Le compilateur va interprter lastrisque en fonction du contexte. Si linstruction commence par un type de variable, lastrisque servira dclarer un pointeur. Si lastrisque est utilis avec une variable dclare en pointeur dans une instruction qui nest pas une dclaration de variable, lastrisque reprsente une indirection. Si lastrisque se trouve dans une expression mathmatique, sans variable pointeur, elle reprsente loprateur de multiplication. Q Quel est le rsultat de lutilisation de loprateur dadresse avec un pointeur ? R Vous obtenez ladresse du pointeur. Un pointeur nest quune variable qui contient ladresse de la variable sur laquelle il pointe. Q Les variables sont-elles toujours stockes au mme emplacement mmoire ? R chaque excution dun programme, ses variables seront stockes des adresses diffrentes. Vous ne devez pas attribuer une adresse constante un pointeur.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

Quiz
1. Quel oprateur faut-il utiliser pour obtenir ladresse dune variable ? 2. Quel oprateur faut-il utiliser pour obtenir la valeur de la variable pointe ? 3. Quest-ce quun pointeur ? 4. Quest-ce quun accs indirect ? 5. Comment les lments dun tableau sont-ils stocks en mmoire ? 6. Trouvez deux mthodes pour obtenir ladresse du premier lment du tableau data[].

http://fribok.blogspot.com/

7. Si on passe un tableau une fonction, quelles sont les deux mthodes qui permettent dindiquer la n du tableau cette fonction ? 8. Quelles sont les six oprations que lon peut faire sur des pointeurs ? 9. Supposons que lon ait deux pointeurs. Le premier pointe sur le troisime lment dun tableau dentiers, et le second sur le quatrime lment. Quelle valeur obtiendrez-vous en soustrayant le premier pointeur du second ? (Dans ce cas, la taille dun entier sera de 4 octets.) 10. Si le tableau de la question 9 contient des donnes de type double, quel sera le rsultat de la soustraction ? (En supposant que la taille dune donne double soit de 8 octets.)

Exercices
1. crivez la dclaration du pointeur ptr char pour une variable de type char. 2. Soit la variable cout de type int. Comment dclarer et initialiser le pointeur p cout sur cette variable ? 3. Comment peut-on attribuer la valeur 100 la variable cout de la question prcdente en utilisant les deux types daccs : direct et indirect ? 4. En continuant les deux exercices prcdents, comment peut-on afcher les valeurs du pointeur et de la variable pointe ? 5. crivez linstruction qui attribue ladresse de la variable radius de type float un pointeur. 6. Trouvez deux mthodes pour attribuer la valeur 100 au troisime lment du tableau data[]. 7. crivez la fonction somtabs() qui, recevant deux tableaux en argument, additionne la valeur des lments des deux tableaux, puis renvoie le rsultat au programme appelant. 8. crivez un programme simple utilisant la fonction de lexercice 7. 9. crivez la fonction addtabs() qui recevra deux tableaux de mme taille. Elle devra additionner les lments correspondants des deux tableaux, et placer le rsultat de la somme dans un troisime tableau de mme taille. 10. TRAVAIL PERSONNEL : Modiez la fonction de lexercice 9 pour quelle renvoie le pointeur du tableau contenant les rsultats. Placez cette fonction dans un programme qui afchera les valeurs des trois tableaux.

http://fribok.blogspot.com/

Exemple pratique 3

Une pause

Nous abordons la troisime section de ce type. Vous savez que lobjectif en est de prsenter un programme complet plus fonctionnel que les exemples des chapitres. Ce programme comporte trs peu dlments inconnus, vous naurez donc aucune difcult le comprendre. Prenez le temps de tester ce code en le modiant ventuellement et en observant les rsultats. Attention aux fautes de frappe qui ne manqueront pas de provoquer des erreurs de compilation. Listing Exemple pratique 3 : secondes.c
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: /* secondes.c */ /* Programme qui fait une pause. */ #include <stdio.h> #include <stdlib.h> #include <time.h> void mon_sleep( int nbr_seconds ); int main( void ) { int x; int wait = 13; /* Pause pendant un nombre de secondes dtermin. On affiche * * un point pour chaque seconde de pause. */ printf("Pause pendant%d secondes\n", wait ); printf(">");

http://fribok.blogspot.com/

21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:

for (x=1; x <= wait; x++) { printf("."); /* affichage dun point */ fflush(stdout); /* on force laffichage du point sur les*/ /* machines qui utilisent la mmoire tampon*/ mon_sleep( 1 ); /* pause dune seconde */ } printf( "Fin!\n"); exit(EXIT_SUCCESS); } /* Pause pendant un nombre de secondes dtermin*/ void mon_sleep( int nbr_seconds ) { clock_t goal; goal = ( nbr_seconds * CLOCKS_PER_SEC )+ clock(); while( goal > clock() ) { ; /* loop */ } }

Analyse Ce listing utilise la fonction mon sleep() (par similarit avec la fonction systme sleep() que vous pourrez reprendre dans vos travaux de programmation). Elle permet de mettre en pause lordinateur pendant un temps dtermin. La seule activit de ce dernier pendant la pause est den contrler la dure. Cette fonction, ou une de ses variantes, a de nombreuses applications. cause de la vitesse dexcution des machines, vous aurez souvent besoin, par exemple, dintroduire une pause pour que lutilisateur ait le temps de lire les informations prsentes lcran (afchage dun copyright la premire excution dune application). Pour illustrer ce processus, le programme afche un point aprs chaque pause dune seconde obtenue avec la fonction mon sleep(). Vous pouvez vous amuser augmenter la dure de cette pause pour contrler la "prcision" de votre ordinateur avec un chronomtre. Vous pouvez aussi transformer ce programme pour imprimer des points (ou toute autre valeur) pendant un certain temps. Remplacez la ligne 38 par la ligne suivante :
printf("x");

http://fribok.blogspot.com/

10
Caractres et chanes
Un caractre peut tre une lettre, un chiffre, une marque de ponctuation ou tout autre symbole. Une chane est une squence de caractres qui permet de manipuler des textes. Aujourdhui, vous allez apprendre :

Utiliser le type de donne char pour travailler avec des caractres Crer des tableaux de type char pour stocker des chanes de caractres Initialiser les caractres et les chanes Utiliser les pointeurs avec les chanes Lire et imprimer des caractres ou des chanes

http://fribok.blogspot.com/

Le type de donne char


En langage C, char est le type de donne permettant de stocker des caractres. Nous avons vu, au Chapitre 3, que char fait partie des types de donnes numriques. Le choix de ce type numrique pour stocker des caractres est li la faon dont le langage C stocke ses caractres. La mmoire de lordinateur conserve toutes les donnes sous forme numrique. Il nexiste pas de mthode pour stocker directement des caractres. Chaque caractre possde son quivalent en code numrique : c est le code ASCII (American Standart Code for Information Interchange). Ce code attribue les valeurs 0 255 aux lettres majuscules et minuscules, aux chiffres, aux marques de ponctuation et autres symboles. Vous trouverez en Annexe A, la totalit de ce code. Par exemple, 97 est lquivalent ASCII de la lettre a. Quand vous stockez le caractre a dans une variable de type char, vous stockez en ralit la valeur 97. La question que lon peut maintenant se poser est : comment le programme sait-il si une variable de type char est un caractre ou un nombre ? Lutilisation le dira :

Si une variable char est utilise un endroit du programme o un caractre est attendu, elle sera interprte comme un caractre. Si une variable char est utilise un endroit du programme o un nombre est attendu, elle sera interprte comme un nombre.

Les variables caractre


Comme toutes les autres variables, une variable char doit tre dclare , et elle peut tre initialise dans la mme instruction :
char a, b, c;/* /* char code = x;/* /* code = !;/* Dclaration de trois variables char non */ initialises */ Dclaration dune variable char appele code */ dans laquelle on stocke le caractre x */ On stocke le caractre! dans la variable code */

Pour crer des constantes caractre, le caractre doit tre entour de guillemets simples. Le compilateur le convertit automatiquement dans le code ASCII correspondant et la valeur du code est attribue la variable. Vous pouvez crer des constantes caractre symboliques en utilisant lordre #define ou le mot cl const.
#define IX x char code = IX;/* code gal x */ const char A = Z;

http://fribok.blogspot.com/

Le Listing 10.1 vous montre la nature numrique du stockage des caractres en utilisant la fonction printf(). Cette fonction permet dafcher indiffremment des caractres ou des nombres. %c dans la chane format demande printf() dafcher un caractre, alors que %d demande un entier dcimal. Le Listing 10.1 initialise deux variables de type char et les afche en mode caractre, puis en mode numrique. Listing 10.1 : Dmonstration de la nature numrique des variables de type char
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: En En En En /* Dmonstration de la nature numrique des variables char */ #include <stdio.h> #include <stdlib.h> /* Dclaration et initialisation de deux variables char */ char c1 = a; char c2 = 90; int main() { /* Affichage de la variable c1 comme caractre, puis comme nombre printf("En mode caractre,la variable c1 est%c\n", c1); printf("En mode nombre, la variable c1 est%d\n", c1); /* La mme chose pour la variable c2 */ printf("En mode caractre, la variable c2 est%c\n", c2); printf("En mode nombre, la variable c2 est%d\n", c2); exit(EXIT_SUCCESS); } mode mode mode mode caractre, nombre, la caractre, nombre, la la variable variable c1 la variable variable c2 c1 est a est97 c2 est Z est 90

*/

La valeur dune variable de type char est comprise entre 128 et 127 (voir Tableau 3.2) alors que le code ASCII attribue les valeurs 0 255. En fait, ce code est divis en deux. Le code ASCII standard est compris entre 0 et 127. Il permet de coder les lettres, les chiffres, la ponctuation et autres symboles du clavier. Le code ASCII tendu (128 255) reprsente tous les caractres spciaux et symboles graphiques (liste en Annexe A).Vous pouvez donc utiliser des variables de type char pour du texte standard. Pour afcher des caractres ASCII tendus, il faudra dclarer des variables de type unsigned char.

http://fribok.blogspot.com/

Listing 10.2 : Afchage des caractres ASCII tendus


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le Le /* Affichage des caractres ASCII tendus */ #include <stdio.h> #include <stdlib.h> unsigned char x;/* unsigned pour ASCII tendu */ int main() { /* Affichage des caractres ASCII tendus de 180 203 */ for (x = 180; x < 204; x++) { printf("Le code ASCII%d correspond au caractre%c\n", x, x); } exit(EXIT_SUCCESS); } ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII ASCII 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond correspond au au au au au au au au au au au au au au au au au au au au au au au au caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre caractre

g

code code code code code code code code code code code code code code code code code code code code code code code code

Analyse La ligne 5 de ce programme dclare une variable de type unsigned char. Cela nous donne un intervalle de valeurs compris entre 0 et 255. Comme pour les autres types de donnes numriques, vous ne devez pas initialiser une variable char avec une valeur qui nappartient pas lintervalle autoris. La variable x est initialise 180 en ligne 11. Chaque excution de linstruction for incrmente la valeur de x de 1, jusqu la valeur 204. Cette boucle afche chaque fois la valeur numrique de x et le caractre ASCII correspondant.

http://fribok.blogspot.com/

eils Cons

faire Utiliser %c pour afcher lquivalent caractre dun nombre. ne pas faire Utiliser les guillemets " " pour initialiser une variable caractre. faire Utiliser les guillemets simples (apostrophes) pour initialiser une variable caractre. ne pas faire Stocker la valeur dun caractre ASCII tendu dans une variable signed char. faire tudier les caractres ASCII de lAnnexe A pour savoir ce que vous pouvez afcher.

Les chanes
Les variables de type char ne peuvent recevoir quun caractre, leur utilisation est donc limite. Il nexiste pas de type de donne pour les chanes de caractres. Un nom ou une adresse sont des exemples de chanes de caractres. Le langage C manipule ce genre dinformations laide des tableaux de caractres.

Tableaux de caractres
Pour stocker une chane de six caractres, il faut dclarer un tableau de type char avec sept lments :
char chaine[7];

Une chane est une squence de caractres qui se termine par le caractre nul \0. Cest le septime lment. Bien quil soit reprsent par deux caractres (antislash et zro), le caractre nul est interprt comme un seul caractre et sa valeur ASCII est 0. Si un programme C stocke la chane Alabama, il stocke les sept caractres A, l, a, b, a, m et a, suivis du caractre nul. Il faut donc un tableau de huit lments. La taille dune variable de type char est de un octet. Le nombre doctets dun tableau de caractres sera donc gal au nombre dlments.

http://fribok.blogspot.com/

Initialiser les tableaux de caractres


Les tableaux de caractres peuvent tre initialiss dans linstruction de dclaration de cette faon :
char chaine[10] = { A, l, a, b, a, m, a, \0};

Vous pouvez aussi utiliser la chane littrale, squence de caractres entre guillemets, qui est plus facile crire et lire :
char chaine[10] = "Alabama";

Dans ce cas, le compilateur ajoute automatiquement le caractre nul la n de la chane. De mme, si la taille du tableau na pas t indique, le compilateur la calculera. La ligne suivante, par exemple, cre et initialise un tableau de huit lments :
char chaine[] = "Alabama";

Le caractre nul permet aux fonctions qui manipulent des chanes de caractres de connatre la longueur de la chane. Si vous lavez oubli, la fonction na aucun autre moyen de dterminer la n de la chane ; elle va continuer traiter les donnes en mmoire tant quelle ne rencontre pas de caractre nul.

Chanes et pointeurs
Une chane de caractres est stocke dans un tableau de type char, et la n de cette chane est reprsente par le caractre nul. Pour dnir une chane, il suft donc de pointer au dbut de cette chane. Lutilisation du nom du tableau dans lequel elle est stocke, non suivi de crochets, est la mthode standard daccs une chane de caractres. La bibliothque standard de C contient de nombreuses fonctions qui manipulent des chanes de caractres. Pour passer une chane en argument, la fonction sattend recevoir le nom du tableau dans lequel elle est stocke. Cest la mthode utiliser avec les fonctions de la bibliothque, en particulier avec printf() et puts() que nous avons tudies.

Les chanes sans tableaux


Nous venons de voir que le nom du tableau qui contient la chane est un pointeur sur le dbut de la chane, et que le caractre nul reprsente la n de cette chane. Le rle du tableau ne consiste qu fournir de la place mmoire pour stocker la chane de caractres. Pour se passer du tableau, il faut pouvoir sallouer de la place mmoire, dnir un pointeur en dbut de chane et placer le caractre nul la n. Il existe deux mthodes : dans la

http://fribok.blogspot.com/

premire, pour une chane littrale dont la taille est dnie au moment de la compilation du programme, la mmoire est alloue une bonne fois pour toutes au lancement du programme. La seconde consiste utiliser la fonction malloc() qui alloue la mmoire au moment de lexcution du programme ; le procd sappelle allocation dynamique.

Allouer la mmoire ncessaire la compilation


Le dbut de la chane est reprsent par un pointeur vers une variable char. Par exemple :
char *message;

Cette instruction dclare le pointeur message vers une variable de type char, mais le pointeur ne pointe encore sur rien. Si vous crivez :
char *message = "Le fantme \du grand Csar!";

vous obtenez le stockage de la chane de caractres Le fantme du grand Csar! (avec un caractre nul la n) quelque part en mmoire, et le pointeur message est initialis pour pointer sur le premier caractre. Il est inutile de connatre lemplacement mmoire exact qui est gr par le systme. Vous allez utiliser le pointeur pour accder la chane. Voici une instruction quivalente la prcdente :
char message[] = "Le fantme \du grand Csar!";

Cette mthode dallocation de mmoire est parfaite quand vous connaissez vos besoins en crivant le programme. Si le programme doit lire la chane de caractres partir du clavier, par exemple, vous ne pourrez pas prvoir la taille de cette chane. Il faudra utiliser la fonction malloc() pour allouer la mmoire de faon dynamique.

La fonction malloc()
La fonction malloc() est une des fonctions de C qui permettent de rserver de lespace mmoire. On lui transmet en argument le nombre doctets ncessaires, elle se charge de trouver et de rserver un bloc de mmoire libre, puis renvoie ladresse du premier octet de ce bloc au programme appelant. La donne renvoye par la fonction malloc() est un pointeur de type void. Un pointeur de ce type sera compatible avec tous les types de donnes.

Syntaxe de la fonction malloc()


#include <stdlib.h> void *malloc(size_t taille);

http://fribok.blogspot.com/

La fonction malloc() rserve un bloc de mmoire du nombre doctets indiqu dans taille. Cette mthode dallocation de mmoire permet doptimiser la gestion de la mmoire de votre ordinateur. Lappel de cette fonction ne peut se faire que si vous avez inclus le chier en-tte stdlib.h. La valeur renvoye par malloc() est un pointeur vers le bloc de mmoire qui a t rserv. Si la recherche de la mmoire a chou, la valeur renvoye est nulle. Il est donc ncessaire de contrler cette valeur mme si la taille de la mmoire demande est petite. Exemple 1
#include <stdlib.h> #include <stdio.h> int main() { /* Allocation de mmoire pour une chane de 100 caractres */ char *ch; if ((ch = malloc(100*sizeof(*ch))) == NULL) { printf("Il ny a pas assez de mmoire \n"); exit (EXIT_FAILURE); } printf("La mmoire est alloue!"\n ); exit(EXIT_SUCCESS); }

Exemple 2
/* Allocation de mmoire pour un tableau de 50 entiers */ int *nombres; nombres = malloc(50 * sizeof(*nombres));

Exemple 3
/* Allocation de mmoire pour un tableau de 10 valeurs virgule flottante */ float *nombres; nombres = malloc(10 * sizeof(*nombres));

Utilisation de malloc()
malloc() peut servir rserver de la mmoire pour un seul caractre. On dclare un pointeur vers une variable de type char:
char *ptr;

http://fribok.blogspot.com/

On appelle la fonction en lui passant la taille du bloc mmoire dsir. Une variable de type char a une taille dun octet et la valeur renvoye sera attribue au pointeur :
ptr = malloc(1);

Cet octet rserv na pas de nom, ptr est donc le seul moyen dy accder. Pour y stocker le caractre x, vous devez crire :
*ptr = x;

Pour rserver la mmoire ncessaire une chane de caractres, la procdure est identique, mais il faut dterminer la taille maximale de cette chane. Notre exemple consiste rserver de la mmoire pour une chane de 99 caractres, plus un pour le caractre nul. On commence en dclarant un pointeur vers une variable char, puis on appelle la fonction :
char *ptr; ptr = malloc(100*sizeof(*ptr));

ptr pointe maintenant sur un bloc de 100 octets qui peut recevoir une chane de caractres. Avec la fonction malloc(), la mmoire nest rserve quau moment o on en a besoin. Bien sr, la mmoire nest pas innie. La taille de la mmoire disponible dpend de la taille de la mmoire installe sur votre ordinateur et des besoins des autres programmes en cours dexcution. Si la mmoire libre nest pas sufsante, la fonction malloc() renvoie la valeur 0. Votre programme doit tester cette valeur pour vrier que la mmoire demande bien t attribue. Vous pouvez tester la valeur renvoye par malloc() en la comparant la constante symbolique NULL qui est dnie avec stdlib.h. Listing 10.3 : La fonction malloc()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: /* Utilisation de la fonction malloc() pour rserver de la */ /* mmoire pour une chane. */ #include <stdio.h> #include <stdlib.h> char count, *ptr, *p; int main() { /* Allocation dun bloc de 35 octets. Test du rsultat. */ /* La fonction de bibliothque exit() termine le programme. */ ptr = malloc(35 * sizeof(*ptr)); if (ptr == NULL) { puts("Erreur dallocation de la mmoire.");

http://fribok.blogspot.com/

Listing 10.3 : La fonction malloc() (suite)


19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: } exit(EXIT_FAILURE);

/* On stocke dans la chane les valeurs 65 90, */ /* qui sont les codes ASCII de A-Z. */ /* p est un pointeur qui permet de se dplacer dans la chane. */ /* ptr pointe toujours sur le dbut de la chane. */

p = ptr; for (count = 65; count < 91; count++) *p++ = count; /* On ajoute le caractre nul de fin. */ *p = \0; /* Affichage de la chane sur lcran. */ puts(ptr); exit(EXIT_SUCCESS); }

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Analyse Ce programme est un exemple dutilisation simple de la fonction malloc(). Il contient de nombreuses lignes de commentaires qui expliquent son fonctionnement. La ligne 5 appelle le chier en-tte stdlib.h pour la fonction malloc() et la ligne 4 appelle stdio.h pour la fonction puts(). La ligne 7 dclare la variable char et les deux pointeurs qui seront utiliss par le programme. Aucune de ces variables nest encore initialise. La ligne 14 appelle la fonction malloc() en lui transmettant le paramtre 35 multipli par la taille du type, savoir dans notre cas celle de char. Il aurait t possible de mettre sizeof(char) au lieu de sizeof(*ptr) ligne 14, ce que lon trouve dailleurs assez souvent. Cependant, multiplier par sizeof(char) est inutile car sizeof(char) vaut 1 par dnition en C (attention, ce nest pas le cas dans tous les langages, comme par exemple le Perl). Par contre, si lenvie vous venait de changer le type des lments points par ptr, vous nauriez pas modier la ligne 14 si vous pensez multiplier par la taille de ce type comme nous lavons crit. Loprateur sizeof() offre une mthode simple pour obtenir un code portable.

http://fribok.blogspot.com/

Ne supposez jamais que malloc() a trouv la mmoire que vous lui demandiez. La ligne 16 vous montre comment contrler facilement si votre demande a t satisfaite. Si la valeur de ptr est nulle, les lignes 18 et 19 vous envoient un message derreur et terminent le programme. Le pointeur p est initialis en ligne 29 avec la mme adresse que le pointeur ptr. p est utilis par la boucle for pour stocker les donnes dans le bloc mmoire rserv. La variable count de la ligne 31 est initialise 65 et incrmente de 1 chaque excution de la boucle jusqu la valeur 91. Chaque valeur de count est stocke ladresse pointe par p. Ce pointeur est bien sr incrment chaque fois que count change de valeur. Les valeurs 65 91 correspondent, en code ASCII, aux 26 lettres majuscules de lalphabet. La boucle for se termine quand lalphabet complet a t stock dans les emplacements mmoire points. La ligne 36 stocke le caractre nul la dernire adresse pointe par p. Le pointeur ptr contient toujours ladresse de la premire valeur, A. Vous pouvez maintenant utiliser cet alphabet comme une chane de caractres ; les lettres seront traites une par une jusqu la valeur nulle. La fonction puts() en ligne 40 vous afche les valeurs qui ont t stockes.
eils Cons

ne pas faire Allouer plus de mmoire que ncessaire. Cette ressource nest pas inpuisable, il faut lutiliser avec parcimonie, mme encore aujourdhui o lon compte la mmoire vive en gigaoctets. Essayer de stocker une nouvelle chane de caractres dans un tableau dclar et initialis avec une chane de taille infrieure. Dans cette dclaration, par exemple : char une_chaine[] = "NO"; une chaine pointe sur "NO". Si vous essayez de stocker "YES" dans ce tableau, vous risquez davoir de srieux problmes. Ce tableau contenait trois caractres : N, O et le caractre nul. Si vous y stockez les quatre caractres Y, E, S et nul, vous ne savez pas quelle donne sera crase par le caractre nul.

Afchage de chanes et de caractres


Un programme qui manipule des chanes de caractres a souvent besoin de les afcher lcran. Les deux fonctions utilises sont puts() et printf().

La fonction puts()
La fonction puts() reoit en argument le pointeur vers la chane de caractres quelle va afcher lcran. Cette fonction permet dafcher les chanes littrales aussi bien que les variables, et elle ajoute un retour la ligne la suite de chaque chane qui lui est cone.

http://fribok.blogspot.com/

Listing 10.4 : La fonction puts()


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: /* Affichage de texte lcran avec puts(). */ #include <stdio.h> #include <stdlib.h> char char char char char *message1 *message2 *message3 *message4 *message5 = = = = = "C"; "est le"; "meilleur"; "langage de"; "programmation!";

int main() { puts(message1); puts(message2); puts(message3); puts(message4); puts(message5); exit(EXIT_SUCCESS); }

C est le meilleur langage de programmation!

Analyse puts() est une fonction standard de sortie pour laquelle il faut inclure le chier entte stdio.h. Les lignes 5 9 de ce programme dclarent et initialisent cinq variables message diffrentes. Chacune de ces variables est un pointeur vers un caractre ou une variable chane. Les lignes 13 17 afchent tous les messages avec la fonction puts().

La fonction printf()
Comme puts(), la fonction de bibliothque printf() permet dafcher des textes lcran. Elle utilise pour cela une chane format, qui contient des ordres de conversion et met en forme le texte afcher. Quand ce texte contient une chane de caractres, lordre de conversion utiliser est %s. Quand printf() rencontre lordre de conversion %s dans sa chane format, elle lassocie llment correspondant de sa liste darguments. Cet argument doit tre un pointeur vers

http://fribok.blogspot.com/

le dbut de la chane que lon veut afcher. printf() va afcher tous les caractres partir de cette adresse, jusqu ce quelle rencontre la valeur 0. Par exemple :
char *str = "Un message afficher"; printf("%s", str);

Il est possible dafcher une combinaison de plusieurs chanes de caractres avec du texte littral et/ou des variables numriques.
char *banque = "Banque de France"; char *nom = "Jean Dupont"; int solde = 1000; printf("Le solde la%s de%s est de%d.", banque, nom, solde);

Le message afch lcran sera :


Le solde la Banque de France de Jean Dupont est de 1000.

Tous les dtails concernant lutilisation de cette fonction sont donns dans le Chapitre 14.

Lecture des chanes de caractres


Les deux fonctions de bibliothque fgets() et scanf() compltent les deux prcdentes en permettant la lecture de chanes de caractres entres au clavier. Avant de pouvoir lire une chane, un programme doit prvoir un endroit pour la stocker. Il peut suivre pour cela une des deux mthodes dj tudies : dclarer un tableau ou appeler la fonction malloc().

La fonction fgets()
La fonction fgets() lit une chane de caractres entre au clavier par lutilisateur. Quand cette fonction est appele, elle lit tout ce qui est tap sur le clavier, jusqu ce que lutilisateur enfonce la touche de retour la ligne (touche Entre). La fonction prend en compte le retour la ligne, ajoute un caractre nul en n de chane et renvoie la chane (tronque si ncessaire la taille indique en argument) au programme appelant. Cette chane est stocke ladresse indique par le pointeur de type char qui a t pass fgets(). Pour appeler fgets() dans votre programme, vous devez inclure le chier en-tte stdio.h. Listing 10.5 : Utilisation de fgets() pour lire une chane de donnes entre au clavier
1: 2: 3: 4: /* Exemple dutilisation de la fonction de bibliothque fgets(). */ #include <stdio.h>

http://fribok.blogspot.com/

Listing 10.5 : Utilisation de fgets() pour lire une chane de donnes entre au clavier (suite)
5: /* Allocation dun tableau de caractres pour recevoir les donnes. */ 6: 7: char input[81]; 8: 9: int main() 10: { 11: puts("Saisissez votre texte, puis appuyez sur Entre"); 12: fgets(input,sizeof(input), stdin)); 13: printf("Vous avez tap:%s\n", input); 14: 15: exit(EXIT_SUCCESS); 16: } Saisissez votre texte, puis appuyez sur Entre Cela est un test Vous avez tap Cela est un test

Analyse Le premier argument de la fonction fgets() est lexpression input. input est le nom dun tableau de type char et donc un pointeur vers le premier lment. Le tableau est dclar en ligne 7 avec 81 lments, qui correspondent aux 80 colonnes de votre fentre (la ligne la plus longue possible) plus le caractre nul. Le second argument est la taille maximale accepte. Nous utilisons pour cela la taille du tableau (sizeof(input)). Le troisime argument est un descripteur de ux (que nous retrouverons au chapitre 16). Le descripteur de lentre standard est stdin. La fonction fgets() peut renvoyer une valeur au programme appelant. Cette valeur, qui a t ignore dans le Listing 10.5, est un pointeur de type char qui correspond ladresse de stockage de la chane lue. Cest la mme valeur qui a t transmise la fonction, mais cela permet au programme de tester si une erreur est survenue. Quand on utilise fgets(), ou toute autre fonction qui stocke des donnes laide dun pointeur, il faut tre sr que le pointeur est bien positionn sur un bloc de mmoire rserv. Il est facile de commettre lerreur suivante :
char *ptr; fgets(ptr, sizeof(*ptr)*n, stdin);

Le pointeur ptr a t dclar sans tre initialis ; on ne peut pas savoir o il pointe. La fonction fgets() va donc stocker sa chane de caractre ladresse pointe par ptr en crasant les donnes qui sy trouvent. Vous devez tre vigilant, car le compilateur ne dtecte pas ce genre derreur et peut, au mieux, vous afcher un avertissement (WARNING).

http://fribok.blogspot.com/

Syntaxe de la fonction fgets()


#include <stdio.h> char *fgets(char *str, int taille, FILE *flux);

Avec stdin en troisime argument, fonction fgets() lit une chane de caractres, str, partir de lentre standard (le clavier). Une chane est constitue dune squence de caractres termine par le caractre de retour la ligne. Quand ce caractre est lu, le caractre nul est ajout en n de chane. La fonction fgets() renvoie un pointeur vers la chane quelle vient de lire. En cas de problme, la valeur renvoye est nulle. Exemple
/* exemple fgets() */ #include <stdio.h> #include <stdlib.h> char line[256]; int main() { printf("Entrez une chane de caractres:\n"); fgets(line, sizeof(line), stdin); printf("\nVous avez tap:\n"); printf("%s\n",line); exit(EXIT_SUCCESS); }

ntion Atte

Il existe galement une fonction gets() qui ne prend pour argument quun pointeur vers une chane de caractres. Cette fonction est viter car il ny a aucun contrle sur la longueur de cette chane et lutilisateur risque de dborder, ce qui entranerait des dysfonctionnements.

Lecture de chanes avec la fonction scanf()


La fonction de bibliothque scanf() permet de lire les donnes numriques entres au clavier (Chapitre 7). Pour cela, cette fonction utilise une chane format qui lui indique comment les lire. Si vous introduisez lordre de conversion %s, scanf() pourra lire une chane de caractres. Comme pour la fonction fgets(), on passe scanf() un pointeur vers le bloc mmoire qui contiendra la chane. Pour cette fonction, le dbut de la chane est le premier caractre non blanc qui est lu. Il y a deux manires de lui indiquer la n de la chane. Si %s est utilis dans la chane format, la chane sera lue jusquau premier caractre blanc rencontr (celui-ci ne fera pas partie de la chane). Si la chane format contient %ns (ou n est une constante entire qui indique la longueur du champ), scanf() lira les n caractres, mais sarrtera au premier blanc

http://fribok.blogspot.com/

rencontr sil arrive avant. Pour la mme raison que vous devez utiliser fgets() et non gets(), vous indiquerez imprativement %ns dans la chane format et ne ferez jamais usage de %s avec scanf(). Sinon, cette fonction pourrait lire plus de caractres que la chane ne peut en contenir, impliquant ensuite un comportement inattendu du programme. Vous pouvez lire plusieurs chanes avec la mme fonction scanf(), les rgles prcdentes sappliqueront pour chaque chane. Par exemple :
scanf("%10s%14s%11s", s1, s2, s3);

Si vous tapez janvier fvrier mars en rponse cette instruction, s1 sera gale janvier, s2 fvrier et s3 mars. Si vous tapez septembre en rponse linstruction suivante :
scanf("%3s%3s%3s", s1, s2, s3);

les valeurs de s1, s2 et s3 seront respectivement sep, tem et bre. Si vous ne tapez pas le nombre de chanes requis, la fonction attendra les caractres suivants, et le programme ne continuera que lorsquelle les aura obtenus. Exemple :
scanf("%10s%14s%11s, s1, s2, s3);

Si la rponse cette instruction est :


janvier fvrier

le programme est suspendu et attend la troisime chane spcie dans la chane format. Si vous tapez plus de chanes que nen contient la chane format, les chanes supplmentaires vont rester dans la mmoire tampon du clavier, en attendant la prochaine instruction scanf() ou une autre fonction dentres/sorties. Imaginons, par exemple, que vous rpondiez janvier fvrier mars aux instructions suivantes :
scanf("%10s%14s", s1, s2); scanf("%11s", s3);

la fonction attribuera janvier la chane s1, fvrier la chane s2 et mars s3. La fonction scanf() renvoie une valeur entire gale au nombre dlments lus avec succs. On ignore cette valeur la plupart du temps. Si le programme ne lit que du texte, il faut choisir fgets() plutt que scanf(). Cette dernire est particulirement indique quand vous avez lire une combinaison de textes et de valeurs numriques. Cela est illustr par le Listing 10.7. Noubliez pas quil faut utiliser loprateur dadresse (&) pour lire des variables numriques avec scanf().

http://fribok.blogspot.com/

Listing 10.7 : Lecture de textes et de valeurs numriques avec scanf()


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: /* La fonction scanf(). */ #include <stdio.h> #include <stdlib.h> char lnom[81], fnom[81]; int count, id_num; int main() { /* message pour lutilisateur. */ puts("Entrez vos nom, prnom et matricule spars"); puts("par un espace, puis appuyez sur Entre."); /* Lecture des trois chanes. */ count = scanf("%80s%80s%d", lnom, fnom, &id_num); /* Affichage des donnes. */ printf("%d chanes ont t lues: %s%s%d\n", count, fnom, lnom, id_num); exit(EXIT_SUCCESS); }

Entrez vos nom, prnom et matricule spars par un espace, puis appuyez sur Entre. Jones Bradley 12345 3 chanes ont t lues: Bradley Jones 12345

Analyse Nous avons vu que les paramtres de scanf() sont des adresses de variables. Dans le Listing 10.7, lnom et fnom sont des pointeurs (donc des adresses), mais id num est un nom de variable auquel il faut ajouter loprateur & avant de le transmettre la fonction scanf() (ligne 17).

Rsum
Nous venons dtudier les donnes de type char dans lesquelles on peut stocker un caractre. Chaque caractre est stock sous forme de nombre fourni par le code ASCII. Ce type de variable peut aussi recevoir un nombre entier. Une chane est une squence de caractres termine par un caractre nul. Les chanes permettent de manipuler les donnes texte. En langage C, une chane de longueur n est stocke dans un tableau de type char de n + 1 lments.

http://fribok.blogspot.com/

Les fonctions qui grent la mmoire, comme malloc(), permettent votre programme dallouer dynamiquement de la mmoire. La fonction malloc() va rserver la taille mmoire ncessaire votre programme. Sans ces fonctions, vous seriez oblig destimer la taille de cette mmoire et probablement den rserver plus que ncessaire.

Q&R
Q Quelle est la diffrence entre une chane et un tableau de caractres ? R Une chane est une squence de caractres termine par le caractre nul. Un tableau est une squence de caractres. Une chane est donc un tableau de caractres qui se terminerait par le caractre nul. Si vous dnissez un tableau de type char, le bloc mmoire allou pour ce tableau sera de la taille exacte du tableau. Vous ne pourrez pas y stocker une chane plus longue. Voici un exemple :
char dept[10] = "Ctes dArmor"; /* /* char dept2[10] = "22"; /* /* Faux! la chane est plus longue */ que le tableau */ Correct, mais on rserve de la */ mmoire pour rien */

Si vous dnissez un pointeur vers une donne de type char, ces restrictions ne sappliquent pas. La seule variable stocker est le pointeur, la chane se trouve quelque part en mmoire (vous devez savoir o). Il ny a ni contrainte de longueur ni despace perdu, on peut faire pointer un pointeur sur une chane de nimporte quelle taille. Q Pourquoi vaut-il mieux allouer la mmoire avec malloc() plutt que de dclarer de grands tableaux pour y ranger ses donnes ? R Dclarer de grands tableaux est la mthode la plus facile, mais vous ne faites pas le meilleur usage de votre mmoire. Quand vos programmes vont devenir de plus en plus gros, il sera trs important de ne leur allouer de la mmoire que quand ils en auront besoin. Quand cette mmoire nest plus ncessaire, on peut la librer pour lallouer une autre variable ou tableau dune autre partie du programme. Q Les caractres ASCII tendus sont-ils disponibles sur tous les types de machines ? R La plupart des ordinateurs supportent ces caractres, mais ce nest pas le cas des plus anciens (dont le nombre diminue tous les jours).

http://fribok.blogspot.com/

Q Que se passe-t-il quand on stocke une chane de caractres dans un tableau trop petit ? R Cela peut provoquer une erreur trs difcile localiser. Le compilateur ne la dtectera pas et toutes les donnes en mmoire situes immdiatement aprs le tableau seront crases. Cela peut tre un bloc mmoire non rserv, dautres donnes, ou des informations vitales pour votre ordinateur. La gravit du rsultat dune telle manuvre dpendra de limportance des donnes perdues.

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

Quiz
1. Quelles sont les valeurs numriques correspondant aux caractres ASCII ? 2. Comment le compilateur C interprte-t-il un caractre entour de guillemets simples ? 3. Quelle est la dnition C dune chane ? 4. Quest-ce quune chane littrale ? 5. Pourquoi faut-il dclarer un tableau de n + 1 lments pour stocker une chane de longueur n ? 6. Comment le compilateur C interprte-t-il une chane littrale ? 7. En utilisant le tableau des caractres ASCII de lAnnexe A, trouvez les valeurs numriques correspondant aux caractres suivants : a) a. b) A. c) 9. d) un blanc. e) . f) F 8. En utilisant le tableau des caractres ASCII de lAnnexe A, trouvez les caractres qui correspondent aux valeurs numriques suivantes : a) 73. b) 32.

http://fribok.blogspot.com/

c) 99. d) 97. e) 110. f) 0. g) 2. 9. Combien doctets faudra-t-il allouer pour stocker les variables suivantes ? (En supposant quun caractre reprsente un octet.) a) char *ch1 = { chane 1 };. b) char ch2[] = { chane 2 };. c) char chane3;. d) char ch4[20] = { cela est la chane 4 };. e) char ch5[20];. 10. Soit linstruction :
char *string = "Une chane!";

Dduisez-en la valeur des expressions : a) string[0]. b) *string. c) string[11]. d) string[33]. e) *string+8. f) string.

Exercices
1. crivez la dclaration de la variable lettre de type char en linitialisant avec le caractre $. 2. crivez la ligne de code qui dclare un tableau de type char en linitialisant avec la chane "les pointeurs sont fous !". La taille de ce tableau doit tre juste sufsante pour y stocker la chane. 3. crivez linstruction qui permet de rserver un bloc mmoire pour stocker la chane "les pointeurs sont fous !". 4. crivez le code qui permet de rserver un bloc mmoire pour stocker une chane de 80 caractres, lire cette chane au clavier et la stocker dans lespace allou.

http://fribok.blogspot.com/

5. crivez une fonction qui copie le contenu dun tableau dans un autre (utilisez les exemples du Chapitre 9). 6. crivez une fonction qui lit deux chanes de caractres. Comptez le nombre de caractres qui les composent et renvoyez un pointeur vers la chane la plus longue. 7. TRAVAIL PERSONNEL : crivez une fonction qui lit deux chanes. Utilisez la fonction malloc() pour allouer la mmoire ncessaire au stockage des deux chanes concatnes. Renvoyez le pointeur de la nouvelle chane. 8. CHERCHEZ LERREUR :
char une_chaine[10] = "cela est une chane";

9. CHERCHEZ LERREUR :
char *quote[100] = { "Souriez, Vendredi sera bientt l!"};

10. CHERCHEZ LERREUR :


char *string1; char *string2 = "second"; string1 = string2;

11. CHERCHEZ LERREUR :


char string1[]; char string2[] = "second"; string1 = string2;

12. TRAVAIL PERSONNEL : En utilisant le tableau de correspondance des caractres ASCII, crivez un programme qui afche une bote lcran avec les caractres doublelignes.

http://fribok.blogspot.com/

11
Les structures
La ralisation de nombreuses tches de programmation se trouve simplie par les structures. Une structure est une mthode de sauvegarde des donnes choisie par le programmeur ; elle rpond donc exactement aux besoins du programme. Aujourdhui, vous allez tudier :

ce que reprsente une structure simple ou complexe ; la dnition et la dclaration des structures ; le mode daccs aux donnes des structures ; la cration des structures pour stocker des tableaux et des tableaux des structures ; la dclaration de pointeurs dans les structures et de pointeurs vers de structures ; le passage de structures en arguments de fonctions ; la dnition, la dclaration et lutilisation des unions ; lutilisation de dnitions types avec les structures.

http://fribok.blogspot.com/

Les structures simples


Une structure contient une ou plusieurs variables groupes sous le mme nom pour tre traites comme une seule entit. Contrairement aux variables stockes dans un tableau, les variables dune structure peuvent tre de types diffrents. Une structure peut contenir tous les types de donnes C, y compris les tableaux et les autres structures. Chaque variable dune structure est appele membre de cette structure. Le paragraphe qui suit vous en donne un exemple simple.

La dnition et la dclaration des structures


Le code dun programme graphique doit travailler avec les coordonnes des points de lcran. Ces coordonnes sont reprsentes par une abscisse x pour la position horizontale, et une ordonne y pour la position verticale. Vous pouvez dnir une structure coord contenant les valeurs x et y dun cran de cette faon :
struct coord { int x; int y; };

Le mot cl struct identie le dbut de la structure et informe le compilateur que coord est le type de structure. Les accolades renferment la liste des variables membres de la structure. Chaque membre doit tre dni par un type de variable et un nom. Notre exemple dnit une structure coord qui contient deux variables entires x et y, mais ne dclare pas de structure. Il y a deux faons de dclarer les structures. La premire consiste faire suivre la dnition dune liste de noms de plusieurs variables :
struct coord { int x; int y; } premier, second;

Ces instructions dnissent la structure de type coord et dclarent deux structures appeles premier et second appartenant au type coord. premier contient deux membres entiers appels x et y, tout comme second. La seconde mthode consiste dclarer les variables de la structure dans une autre partie du code du programme. Voici une autre syntaxe pour dclarer deux structures de type coord:
struct coord { int x; int y; };

http://fribok.blogspot.com/

/* instructions ... */ struct coord premier, second;

Laccs aux membres dune structure


Chaque membre dune structure peut tre utilis comme une variable isole du mme type. Pour faire rfrence un membre particulier, on spare le nom de la structure concerne de celui du membre vis, avec l oprateur (.). Pour que la structure premier reprsente le point de lcran de coordonnes x=50, y=100, on utilise la syntaxe suivante :
premier.x=50; premier.y=100;

Linstruction suivante permet dafcher les coordonnes dcran stockes dans la structure second:
printf("%d,%d", second.x, second.y);

Le principal avantage des structures sur les variables est la possibilit de copier des informations entre structures de mme type par une seule instruction simple. Dans le cas de notre exemple prcdent, linstruction :
premier = second;

est quivalente aux deux instructions suivantes :


premier.x = second.x; premier.y = second.y;

Quand un programme utilise des structures complexes, possdant de nombreux membres, cette notation permet de gagner beaucoup de temps. Les autres avantages des structures apparatront chaque fois que des informations reprsentes par des types de variables diffrents devront tre traits comme une seule entit. Dans une base de donnes destine un mailing, par exemple, chaque adresse sera une structure et les informations qui la constituent (nom, prnom, ville, etc.) en seront les membres. Syntaxe du mot cl struct
struct nom_modle { membre(s); /* instructions */ } occurrence;

Le mot cl struct permet de dclarer la structure. Une structure contient une ou plusieurs variables (membre(s)) groupes sous un mme nom pour tre traites comme une seule

http://fribok.blogspot.com/

entit. Ces variables peuvent tre de nimporte quel type : tableaux, pointeurs ou autres structures. Le mot cl struct indique au compilateur le dbut de la dnition dune structure. Il est suivi du nom du modle de la structure, puis des membres entre accolades. Il est possible de dnir une ou plusieurs occurrences qui constituent les dclarations de structures. Une dnition ne comportant pas de dclaration ne sert que de modle pour les structures qui seront dclares plus loin dans le programme. Une dnition simple doit respecter la syntaxe suivante :
struct nom { membre(s); /* instructions ... */ };

Pour faire rfrence ce modle, la dclaration scrira :


struct nom occurrence;

Exemple 1
/* dclaration dun modle de structure appel SSN */ struct SSN { int premier_trois; char dash1; int second_deux; char dash2; int dernier_quatre; } /* utilisation du modle */ struct SSN client_ssn;

Exemple 2
/* Dclaration complte dune structure */ struct date { char jour[2]; char mois[2]; char an[4]; } date_jour;

Exemple 3
/* Dfinition, dclaration et initialisation dune structure */ struct heure { int heures; int minutes; int seconds; } heure_naissance = { 8, 45, 0 };

http://fribok.blogspot.com/

Les structures plus complexes


Aprs avoir introduit les structures simples, nous pouvons tudier des types de structures plus intressants. Ce sont les structures dont les membres sont dautres structures ou des tableaux.

Structures contenant des structures


Les membres dune structure peuvent tre dautres structures. Reprenons lexemple prcdent. Supposons que votre programme ait besoin de traiter des rectangles. Un rectangle peut tre reprsent par les coordonnes de deux coins diagonalement opposs. Nous avons vu comment dnir une structure pour enregistrer un point laide de ses deux coordonnes. Pour dnir le rectangle, nous avons besoin de deux structures telles que celle-ci. La structure coord ayant dj t dnie, vous pouvez dnir la deuxime avec les instructions suivantes :
struct rectangle { struct coord hautgauche; struct coord basdroite; };

La structure de type rectangle contient deux structures appartenant au type coord: hautgauche et basdroite. Ces instructions ne constituent que le modle de la structure, pour la dclarer, vous devez inclure une instruction du type :
struct rectangle maboite;

Vous auriez pu combiner dnition et dclaration de cette faon :


struct rectangle { struct coord hautgauche; struct coord basdroite; } maboite;

Pour accder aux membres de type int de deux structures imbriques, il faut utiliser deux fois loprateur (.) : maboite.hautgauche.x. Cette expression fait rfrence au membre x du membre hautgauche de la structure maboite appartenant au type rectangle. Lexemple suivant est le code qui dcrit un rectangle de coordonnes (0, 10), (100, 200) :
maboite.hautgauche.x = 0; maboite.hautgauche.y = 10; maboite.basdroite.x = 100; maboite.basdroite.y = 200;

http://fribok.blogspot.com/

La Figure 11.1 vous explique les relations existant entre les diffrents membres et variables de cet exemple.
Figure 11.1 Relations entre une structure, des structures imbriques et les membres de celles-ci.

Variable de type int (x)

{ Variable de type int (y) { { Variable de type int (y) {

maboite.hautgauche.x maboite.hautgauche.y

{ {

Structure de type coord (hautgauche)

Variable de type int (x)

maboite.basdroite.x maboite.basdroite.y

Structure de type coord (basdroite)

Structure de type rectangle (maboite)

Examinons le programme du Listing 11.1 qui nous prsente un exemple de structures imbriques. Ce programme demande lutilisateur les coordonnes dun rectangle pour en calculer laire et lafcher. Listing 11.1 : Exemple de structure contenant une structure
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: /* Exemple de structures imbriques. */ /* Ce programme reoit les coordonnes des coins dun rectangle et en calcule laire. On suppose que la coordonne y du coin suprieur gauche est plus grande que la coordonne y du coin infrieur droit, que la coordonne x du coin infrieur droit est plus grande que la coordonne x du coin suprieur gauche, et que toutes les coordonnes sont positives. */ #include <stdio.h> #include <stdlib.h> int longueur, largeur; long aire; struct coord{ int x; int y; }; struct rectangle{ struct coord hautgauche; struct coord basdroit; } maboite; int main() { /* Lecture des coordonnes */

http://fribok.blogspot.com/

29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:

printf("\nEntrez la coordonne x du coin suprieur gauche : "); scanf("%d", &maboite.hautgauche.x); printf("\nEntrez la coordonne y du coin suprieur gauche : "); scanf("%d", &maboite.hautgauche.y); printf("\nEntrez la coordonne x du coin infrieur droit : "); scanf("%d", &maboite.basdroit.x); printf("\nEntrez la coordonne y du coin infrieur droit : "); scanf("%d", &maboite.basdroit.y); /* Calcul de la longueur et de la largeur */ largeur = maboite.basdroit.x maboite.hautgauche.x; longueur = maboite.basdroit.y maboite.hautgauche.y; /* Calcul et affichage de laire */ aire = largeur * longueur; printf("\nLaire du rectangle est de%ld units.\n", aire); exit(EXIT_SUCCESS); } la la la la du coordonne x du coin suprieur coordonne y du coin suprieur coordonne x du coin infrieur coordonne y du coin infrieur rectangle est de 81 units. gauche: 1 gauche: 1 droit: 10 droit: 10

Entrez Entrez Entrez Entrez Laire

Analyse La structure coord est dnie aux lignes 15 18 de ce programme avec ses deux membres : x et y. Les lignes 20 23 dclarent et dnissent la structure maboite appartenant au type rectangle. Les deux membres de la structure rectangle, hautgauche et basdroit, sont des structures de type coord. Le programme demande les coordonnes du rectangle lutilisateur pour les stocker dans la structure maboite (lignes 29 39). Ces coordonnes sont au nombre de quatre, chaque structure hautgauche et basdroit ayant deux membres correspondant aux coordonnes x et y. Pour le calcul de laire, x et y tant dans une structure imbrique, il faut associer le nom des deux structures pour accder leur valeur : maboite.basdroit.x ou y, et maboite.hautgauche.x ou y. Le langage C nimpose aucune limite quant au nombre de structures que lon peut imbriquer. Le bon sens et la mmoire disponible vous feront rarement dpasser trois niveaux dimbrication en crivant vos programmes.

http://fribok.blogspot.com/

Les tableaux membres de structures


Vous pouvez dnir une structure constitue dun ou de plusieurs tableaux. Les tableaux peuvent contenir tous les types de donnes C. Les instructions suivantes, par exemple, dnissent un modle de structure data qui contient un tableau dentiers de 4 lments appel x, et un tableau de caractres de 10 lments appel y:
struct data{ int x[4]; char y[10]; };

Vous pouvez ensuite dclarer une structure record appartenant au type data avec linstruction :
struct data record;

La Figure 11.2 reprsente cette structure de tableaux. Vous pouvez remarquer que les lments du tableau x occupent deux fois plus de place mmoire que les lments du tableau y. En effet, une donne de type int occupe deux octets en mmoire alors quune donne de type char nen occupe quun.
Figure 11.2 Organisation dune structure contenant des tableaux.
record.x[0] record record record record.y[8]

Pour accder aux lments de tableaux qui sont membres dune structure, on associe le nom du membre et lindex du tableau :
record.x[2] = 100; record.y[1] = x;

Nous avons vu que les tableaux de caractres sont utiliss le plus souvent pour stocker des chanes, et que le nom du tableau sans les crochets est un pointeur vers le premier lment du tableau. Nous pouvons en dduire que record.y est un pointeur vers le premier lment du tableau y[] de la structure record. Vous pourriez ainsi afcher le contenu de y[] avec la syntaxe suivante :
puts(record.y);

tudions un autre exemple avec le Listing 11.2.

http://fribok.blogspot.com/

Listing 11.2 : Exemple dune structure contenant des tableaux


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 30: 31: 32: /* Exemple dutilisation dune structure qui contient des */ /*tableaux. */ #include <stdio.h> #include <stdlib.h> /* Dfinition et dclaration dune structure pour y ranger les */ /* donnes. Elle contient une variable de type float et deux */ /* tableaux de type char */ struct data{ float montant; char fnom[30]; char pnom[30]; } rec; int main() { /* Lecture des donnes au clavier. */ printf("Entrez les nom et prnom du donateur,\n"); printf("spars par un espace: "); scanf("%30s%30s", rec.fnom, rec.pnom); printf("\nEntrez le montant du don: scanf("%f", &rec.montant); ");

/* On affiche les informations. */ /* Note:%.2f indique quune valeur virgule flottante doit */ /* tre affiche avec deux chiffres aprs la virgule. */ printf("\nLe donateur%s%s a donn%.2f Euros\n", rec.fnom, rec.pnom, rec.montant); exit(EXIT_SUCCESS); }

Entrez les nom et prnom du donateur, spars par un espace: Bradley Jones Entrez le montant du don: 1000.00 Le donateur Bradley Jones a donn 1000.00 Euros

Analyse Ce programme cre une structure qui contient les tableaux fnom[30] et lnom[30]. Ce sont deux tableaux de caractres qui vont contenir respectivement le nom et le prnom des personnes. La structure data est dclare aux lignes 8 12. Ses membres sont les tableaux de caractres fnom[30] et lnom[30], et la variable montant. Cette structure a t cre pour stocker le montant des dons des personnes qui seront enregistres. La structure rec de type data dclare en ligne 12 est utilise par le programme pour demander les valeurs lutilisateur (lignes 18 23) et pour les afcher (lignes 29 et 30).

http://fribok.blogspot.com/

Tableaux de structures
Le langage C est un langage trs puissant et sa facult de crer des tableaux de structures en est un bon tmoignage. Voici pourquoi les tableaux de structures reprsentent un formidable outil de programmation. La dnition dune structure doit "coller" au modle des donnes avec lesquelles le programme doit travailler. En gnral, le programme a besoin de plusieurs modles de donnes. Par exemple, dans un programme qui remplit la fonction de rpertoire tlphonique, vous pouvez dnir une structure contenant le nom et le numro de tlphone de chaque personne :
struct entry{ char fnom[10]; char pnom[12]; };

Une liste telle que celle-ci doit pouvoir recevoir de nombreuses occurrences. La dclaration dune structure de ce type ne sera donc pas trs utile. Pour obtenir un vrai rpertoire il faut crer un tableau de structures de type entry:
struct entry list[1000];

Cette instruction dclare un tableau list de 1000 lments. Chacun de ces lments est une structure de type entry qui sera identie par un index, comme tout lment de tableau. Chacune de ces structures regroupe trois lments qui sont des tableaux de type char. La Figure 11.3 vous donne le diagramme de cette construction complexe. Quand votre tableau de structures est dclar, vous avez de nombreuses possibilits de manipulation des donnes. Par exemple, pour copier un lment de tableau dans un autre, vous pouvez crire :
list[1] = list[5];

Cette instruction attribue chaque membre de la structure list[1] la valeur contenue dans le membre correspondant de list[5]. Il est aussi possible de copier un membre de structure dans un autre :
strcpy(list[1].phone, list[5].phone);

Cette instruction copie la chane stocke dans list[5].phone dans list[1].phone. La fonction strcpy(), que vous tudierez au Chapitre 17, permet de copier une chane dans une autre chane. Une autre manipulation de donne peut tre la copie entre lments de tableaux :
list[5].phone[1] = list[2].phone[3];

http://fribok.blogspot.com/

Figure 11.3 Organisation du tableau de structures.

list[0].fnom[0]

list[0].fnom list[0] list[0].lnom list[0].phone

list[1].fnom list[1] list[1].lnom list[1].phone

list[2].fnom list[2] list[2].lnom list[2].phone

list[999].fnom list[999] list[999].lnom list[999].phone

list[999].phone[2]

Cette instruction copie le deuxime caractre du numro de tlphone de list[5] en quatrime position du numro de tlphone de list[2]. Le Listing 11.3 prsente un exemple de tableau de structures dont les membres sont des tableaux. Listing 11.3 : Tableaux de structures
1: /* Exemple dutilisation des tableaux de structures. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: /* Dfinition dune structure pour stocker les donnes. */ 6: 7: struct entry { 8: char fnom[20]; 9: char pnom[20]; 10: char phone[10]; 11: }; 12: 13: /* Dclaration dun tableau de structures. */ 14: 15: struct entry list[4];

http://fribok.blogspot.com/

Listing 11.3 : Tableaux de structures (suite)


16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: int i; int main() { /* Boucle denregistrement de 4 personnes. */ for (i = 0; i < 4; i++) { printf("\nEntrez le nom: "); scanf("%20s", list[i].fnom); printf("Entrez le prnom: "); scanf("%20s", list[i].pnom); printf("Entrez le numro de tlphone (xxxxxxxx): "); scanf("%10s", list[i].phone); } /* On saute deux lignes*/ printf("\n\n"); /* Affichage des donnes. */ for (i = 0; i < 4; i++) { printf("Nom:%s%s", list[i].pnom, list[i].fnom); printf("\t\tPhone:%s\n", list[i].phone); } return 0; }

Entrez le nom: Jones Entrez le prnom: Bradley Entrez le numro de tlphone: 55591248 Entrez le nom: Aitken Entrez le prnom: Peter Entrez le numro de tlphone: 52976543 Entrez le nom: Jones Entrez le prnom: Melissa Entrez le numro de tlphone: 55983492 Entrez le nom: Dupont Entrez le prnom: Charlotte Entrez le numro de tlphone: 35297651 Nom: Nom: Nom: Nom: Bradley JonesTlphone: Peter AitkenTlphone: Melissa JonesTlphone: Charlotte Dupont Tlphone: 55591248 52976543 55983492 35297651

http://fribok.blogspot.com/

Analyse Ce code source suit le mme format que la plupart de ceux que nous avons dj tudis. Il commence par une ligne de commentaires et inclut le chier stdio.h pour les entres/ sorties. Les lignes 7 11 dnissent un modle de structure appel entry qui contient trois tableaux de caractres : fnom[20], lnom[20], et phone[10]. La ligne 15 utilise ce modle pour dclarer le tableau list contenant quatre structures de type entry. Une variable de type int est dnie en ligne 17 pour servir de compteur au programme. La fonction main() commence en ligne 19 et sa premire fonction est dexcuter quatre fois la boucle for. Le rle de celle-ci est de rcuprer les informations pour le tableau de structures (lignes 24 32). Vous pouvez remarquer que ce tableau utilise un index de la mme faon que les tableaux tudis au Chapitre 8. Le programme marque une pause (ligne 36) en sautant deux lignes lcran avant lafchage des donnes. Les valeurs contenues dans le tableau de structures sont obtenues en utilisant le nom du tableau index associ au nom du membre de la structure par loprateur (.). Il est important de vous familiariser avec les techniques utilises dans le Listing 11.3. De nombreuses tches de programmation gagnent tre ralises en utilisant des tableaux de structures dont les membres sont des tableaux.
eils Cons

faire Dclarer les structures en utilisant les mmes rgles de porte que pour les autres variables (voir Chapitre 12). ne pas faire Oublier dassocier le nom de la structure loprateur (.) pour en utiliser un des membres. Confondre le nom de la structure et le nom du modle de structure auquel elle appartient. Le modle permet de dnir un format, le nom de structure est une variable qui utilise ce format. Oublier le mot cl struct en dclarant une structure appartenant un modle prdni.

Initialisation des structures


Comme tout autre type de variable C, les structures peuvent tre initialises quand elles sont dclares. La procdure suivre est la mme que pour les tableaux. La dclaration est

http://fribok.blogspot.com/

suivie dun signe gal puis, entre accolades, dune liste de valeurs dinitialisation spares par des virgules :
1: struct vente { 2: char client[20]; 3: char article [20]; 4: float montant; 5: }mesventes = { "Acme Industries", 6: "ciseaux gauchers", 7:1000.00 8: };

Lexcution de ces instructions donne les rsultats suivants : 1. Dnition dun type de structure appel vente (lignes 1 5). 2. Dclaration dune structure appele mesventes appartenant au type vente (ligne 5). 3. Initialisation du membre mesventes.client avec la chane "Acme Industries" (ligne 5). 4. Initialisation du membre mesventes.article avec la chane "ciseaux gauchers" (ligne 6). 5. Initialisation du membre mesventes.montant avec la valeur 1000.00 (ligne 7). Dans le cas dune structure dont les membres sont des structures, les valeurs dinitialisation doivent apparatre dans lordre. Elles seront stockes dans les membres en utilisant lordre dans lequel ces membres sont lists dans la dnition de la structure.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: struct client { char societe[20]; char contact[25]; } struct vente { struct client acheteur; char article[20]; float montant; } mesventes = { { "Acme Industries", "George Adams"}, "ciseaux gauchers", 1000.00 };

Lexcution de ces instructions donne les rsultats suivants : 1. Le membre mesventes.acheteur.socit est initialis avec la chane "Acme Indus tries" (ligne 10). 2. Le membre mesventes.acheteur.contact est initialis avec la chane "George Adams" (ligne 10).

http://fribok.blogspot.com/

3. Le membre mesventes.article est initialis avec la chane "ciseaux gauchers" (ligne 11). 4. Le membre mesventes.montant est initialis la valeur 1000.00 (ligne 12). De la mme faon, vous pouvez initialiser les tableaux de structures. Les donnes dinitialisation que vous listerez sont appliques, dans lordre, aux structures du tableau. Pour dclarer, par exemple, un tableau de structures de type vente et initialiser les deux premiers lments (donc, les deux premires structures), vous pouvez crire :
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: struct client { char socit[20]; char contact[25]; }; struct vente { struct client acheteur; char article[20]; float montant; };

struct vente y1990[100] = { { { "Acme Industries", "George Adams"}, "ciseaux gauchers", 1000.00 } { { "Wilson & Co.", "Ed Wilson"}, "peluche type 12", 290.00 } };

Lexcution de ce code donnera les rsultats suivants : 1. Le membre y1990[0].acheteur.socit est initialis avec la chane "Acme Indus tries" (ligne 14). 2. Le membre y1990[0].acheteur.contact est initialis avec la chane "George Adams" (ligne 14). 3. Le membre y1990[0].article est initialis avec la chane "ciseaux gauchers" (ligne 15). 4. Le membre y1990[0].montant est initialis avec la valeur 1000.00 (ligne 16). 5. Le membre y1990[1].acheteur.socit est initialis avec la chane "Wilson & Co." (ligne 18). 6. Le membre y1990[1].acheteur.contact est initialis avec la chane "Ed Wilson" (ligne 18).

http://fribok.blogspot.com/

7. Le membre y1990[1].article est initialis avec la chane "Peluche type 12" (ligne 19). 8. Le membre y1990[1].montant est initialis avec la valeur 290.00 (ligne 20).

Structures et pointeurs
Les pointeurs tant un concept trs important en langage C, il nest pas surprenant de les retrouver avec les structures. Un membre de structure peut tre un pointeur, et vous pouvez dclarer un pointeur vers une structure.

Les pointeurs membres dune structure


Un pointeur qui est un membre dune structure se dclare de la mme faon quun pointeur qui ne lest pas, en utilisant loprateur indirect (*) :
struct data { int *valeur; int *taux; } premier;

Ces instructions dnissent et dclarent une structure dont les deux membres sont des pointeurs vers des variables de type int. Cette dclaration doit tre suivie de linitialisation de ces pointeurs avec les adresses des variables pointes. Si nous supposons que cout et interet sont des variables de type int, linitialisation des pointeurs suit la syntaxe suivante :
premier.valeur = &cout; premier.taux = &interet;

Vous pouvez maintenant utiliser loprateur indirect (*). Lexpression *premier.valeur a la valeur de la variable cout et lexpression *premier.taux a la valeur de la variable interet. Les types de pointeurs les plus souvent utiliss comme membres de structures sont ceux qui pointent sur une chane de caractres. Les instructions suivantes dclarent un pointeur vers une variable char et linitialise pour pointer sur une chane :
char *p_message; p_message = "Le langage C";

La mme opration peut tre ralise si les pointeurs sont des membres de structure :
struct msg { char *p1;

http://fribok.blogspot.com/

char *p2; } myptrs; myptrs.p1 = "Le langage C"; myptrs.p2 = "par Pearson Education";

La Figure 11.4 prsente les rsultats de lexcution de ces instructions. Chaque pointeur membre de la structure pointe sur le premier octet dune chane stocke quelque part en mmoire. Comparez ce schma celui de la Figure 11.3 qui montrait des donnes stockes dans une structure contenant des tableaux de type char.
Figure 11.4 Structure contenant des pointeurs vers des variables de type char.
myptrs myptrs.p1 myptrs.p2 1008 2252

1008 1009....

Le langage C\0
2252 2253....

Par Pearson Education\0

Lutilisation de ce type de pointeur nest pas diffrente de celle des pointeurs hors structure. Pour afcher les chanes de notre exemple, vous pouvez crire :
printf("%s%s", mesptrs.p1, mesptrs.p2);

Quelle diffrence y a-t-il entre un membre de structure qui est un tableau de type char, et un autre membre qui est un pointeur vers une variable de type char? Ce sont deux mthodes de stockage des chanes de caractres dans une structure. La structure suivante utilise les deux mthodes :
struct msg { char p1[30]; char *p2; } myptrs;

Le nom du tableau sans crochets tant un pointeur vers le premier lment du tableau, vous pouvez utiliser les deux membres de la structure de faon similaire :
strcpy(myptrs.p1, "Le langage C"); strcpy(myptrs.p2, "par Pearson Education"); /* instructions ... */ puts(myptrs.p1); puts(myptrs.p2);

http://fribok.blogspot.com/

Si vous dnissez un modle de structure contenant un tableau de type char, chaque structure dclare sur ce modle occupera lespace mmoire correspondant la taille du tableau. En voici un exemple :
struct msg { char p1[10]; char p2[10]; } myptrs; ... strcpy(p1, "Montpellier"); /* /* strcpy(p2, "34");/* /* /*

incorrect, la chane est plus longue */ que le tableau */ correct, mais la chane tant plus */ courte que le tableau, une partie de */ lespace rserv restera inoccup */

Si vous utilisez lautre mthode en dnissant une structure contenant des pointeurs vers des variables de type char, cette contrainte de mmoire nexiste pas. Chaque structure dclare noccupera que lespace mmoire ncessaire au pointeur. Les chanes de caractres sont stockes dans une autre partie de la mmoire, indpendante de la structure. Le pointeur pourra pointer sur une chane de nimporte quelle longueur, celle-ci deviendra une partie de la structure tout en tant stocke en dehors.

Les pointeurs vers des structures


Un programme C peut dclarer et utiliser des pointeurs vers des structures exactement comme il peut dclarer des pointeurs vers tout autre type de donne. Ces pointeurs sont souvent utiliss pour passer une structure comme argument une fonction. Voici comment un programme peut crer et utiliser des pointeurs vers des structures. La premire tape est la dnition de la structure :
struct part { int nombre; char nom[10]; };

La seconde est la dclaration dun pointeur vers une variable de type part.
struct part *p_part;

Le pointeur ne peut tre initialis, car il nexiste pas encore de structure appartenant au type part. Il ne faut pas oublier que la dnition du modle de structure ne rserve pas de mmoire, cest la dclaration dune structure sur ce modle qui le fait. La valeur dun pointeur tant une adresse en mmoire, il faut dclarer une structure de type part avant de pouvoir pointer dessus :
struct part gizmo;

http://fribok.blogspot.com/

Cette instruction permet dinitialiser le pointeur :


p_part = &gizmo;

La valeur du pointeur p part reprsente ladresse de la structure gizmo, tandis que *p part fait directement rfrence gizmo. Pour accder aux membres de la structure gizmo, on utilise loprateur (.) de cette faon :
(*p_part).nombre = 100;

Les parenthses sont ncessaires, car loprateur (.) est prioritaire sur loprateur (*). Cette instruction a attribu la valeur 100 au membre gizmo.nombre.
Figure 11.5 Un pointeur vers une structure pointe sur le premier octet de cette structure.
gizmo.nombre gizmo.nom[]

p-part

Il existe une autre technique pour accder aux membres dune structure avec le pointeur vers cette structure. Cette technique utilise loprateur dindirection, reprsent par le signe moins suivi du signe "suprieur " (>). Cet oprateur est plac entre le nom du pointeur et le nom du membre. Pour accder au membre nombre de gizmo avec le pointeur p part, utilisez la syntaxe suivante :
p_part > nombre

tudions un autre exemple. Soit str une structure, p str un pointeur vers cette structure et memb un membre de str. Vous pouvez atteindre str.memb avec linstruction suivante :
p_str > memb

Il existe ainsi trois mthodes pour accder au membre dune structure :


En utilisant le nom de la structure. Avec un pointeur vers cette structure et loprateur indirect (*). Avec un pointeur vers cette structure et loprateur dindirection (>).

Dans notre exemple, les trois expressions suivantes sont quivalentes :


str.memb (*p_str).memb p_str>memb

http://fribok.blogspot.com/

Pointeurs et tableaux de structures


Les tableaux de structures et les pointeurs de structures sont des outils de programmation trs puissants. On peut les combiner en utilisant les pointeurs pour accder aux structures qui sont des lments de tableaux. Reprenons, pour notre dmonstration, cette dnition de structure :
struct part { int nombre; char nom[10]; };

La structure tant dnie, nous pouvons dclarer un tableau appartenant au type part:
struct part data[100];

Nous pouvons ensuite dclarer un pointeur vers une structure de type part, et linitialiser pour pointer sur la premire structure du tableau data:
struct part *p_part; p_part = &data[0];

Nous aurions pu crire la deuxime instruction de cette faon :


p_part = data;

Nous obtenons un tableau de structures de type part et un pointeur vers le premier lment du tableau. Un programme pourra afcher le contenu de ce premier lment avec linstruction :
printf("%d%s", p_part > nombre, p_part > nom);

Pour afcher tous les lments du tableau, il faudrait utiliser une boucle for et les afcher un par un chaque excution de la boucle. Pour accder aux membres avec la notation pointeur, il faudra changer la valeur de p part pour qu chaque excution de la boucle, ladresse pointe soit celle de llment suivant (donc de la structure suivante). Voici comment raliser cette opration. Nous allons utiliser les pointeurs arithmtiques. Loprateur unaire (++) a une signication particulire quand il est utilis avec un pointeur. Il incrmente la valeur du pointeur, de la taille de lobjet point. Les lments de tableau tant stocks en mmoire de faon squentielle, ces pointeurs arithmtiques sont particulirement appropris. Si, dans un programme, le pointeur pointe sur llment n dun tableau, lemploi de loprateur (++) sur ce pointeur le fera pointer sur llment n+1. La Figure 11.6 nous montre un tableau nomm x[] qui contient des lments

http://fribok.blogspot.com/

ayant une taille de quatre octets (une structure contenant deux membres de type int par exemple). Le pointeur ptr a t initialis pour pointer sur x[0]. Chaque fois que loprateur (++) sera utilis, ptr pointera sur llment suivant.
Figure 11.6 Loprateur ++ positionne le pointeur sur llment suivant.
X[0] X[1] X[2]

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012

1001

Cela signie quun programme peut accder aux lments dun tableau de structures en incrmentant un pointeur. Cette notation est plus facile et plus concise que celle qui utilise lindex. Listing 11.4 : Exemple daccs aux lments successifs dun tableau en modiant un pointeur avec loprateur (++)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: /* Exemple de dplacement dans un tableau de structures */ /* en utilisant un pointeur. */ #include <stdio.h> #include <stdlib.h> #define MAX 4 /* Dfinition dune structure, dclaration et initialisation */ /* dun tableau de 4 structures. */ struct part { int nombre; char nom[10]; } data[MAX] = {1, "Smith", 2, "Jones", 3, "Adams", 4, "Wilson" }; /* Dclaration dun pointeur de structure de type part, */ /* et dune variable compteur. */ struct part *p_part; int count;

http://fribok.blogspot.com/

1005

1009

ptr++

ptr++

Listing 11.4 : Exemple daccs aux lments successifs dun tableau en modiant un pointeur avec loprateur (++) (suite)
25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: A A A A int main() { /* Initialisation du pointeur sur le premier lment du tableau.*/ p_part = data; /* Boucle qui permet de se dplacer dans le tableau */ /* en incrmentant le compteur chaque itration. */ for (count = 0; count < MAX; count++) { printf("A ladresse%d: %d%s\n", p_part, p_part>nombre, p_part>nom); p_part++; } exit(EXIT_SUCCESS); } 96: 1 Smith 108: 2 Jones 120: 3 Adams 132: 4 Wilson

ladresse ladresse ladresse ladresse

Analyse Ce programme commence par dclarer et initialiser le tableau de structures data (lignes 11 18). Il dnit ensuite le pointeur p part qui permettra de pointer sur la structure data (ligne22). La premire action de la fonction main() la ligne29 est de faire pointer p part sur la structure de type part qui a t dclare. La boucle for permet dafcher tous les lments en dplaant le pointeur sur llment suivant chacune de ses itrations de la ligne 34 39). Le programme donne aussi ladresse de chaque lment. Examinez les adresses afches. Leur valeur sera diffrente sur votre systme, mais la diffrence entre deux adresses sera la mme, cest--dire la taille de la structure part (12). Cela dmontre bien que loprateur (++) augmente la valeur du pointeur de la taille de lobjet point.

Le passage de structures comme arguments de fonctions


Le Listing 11.5 vous montre comment passer une structure une fonction. Ce programme a t obtenu en modiant le Listing 11.2 : on utilise une fonction pour afcher les donnes lcran en remplacement des instructions de la fonction main() qui excutaient cette tche.

http://fribok.blogspot.com/

Listing 11.5 : Transmission dune structure une fonction


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: /* Transmission dune structure une fonction. */ #include <stdio.h> #include <stdlib.h> /* Dclaration et dfinition dune structure stockant */ /* les donnes. */ struct data{ float montant; char fnom[30]; char lnom[30]; } rec; /* Prototype de la fonction. Cette fonction ne renvoie pas de */ /* valeur, et son argument est une structure de type data. */ void print_rec(struct data x); int main() { /* Lecture des donnes au clavier. */ printf("Entrez les nom et prnom du donateur,\n"); printf("spars par un blanc: "); scanf("%30s%30s", rec.fnom, rec.lnom); printf("\nEntrez le montant du don: scanf("%f", &rec.montant); /* Appel de la fonction. */ print_rec(rec); exit(EXIT_SUCCESS); } void print_rec(struct data x) { printf("\nLe donateur%s%s a donn%.2f Euros\n", x.fnom, x.lnom, x.montant); } ");

Entrez les nom et prnom du donateur, spars par un blanc: Jones Bradley Entrez le montant du don: 1000.00 Le donateur Jones Bradley a donn 1000.00 Euros

http://fribok.blogspot.com/

Analyse La ligne 16 de ce programme contient le prototype de la fonction qui va recevoir la structure. Largument appropri dans notre cas est une structure de type data. Cet argument est repris la ligne 36, dans len-tte de la fonction. Le passage de la structure se fait en ligne 31, en indiquant son nom dans la liste des arguments de lappel de la fonction. Transmettre une structure une fonction est aussi simple que de passer une variable. La structure aurait pu tre transmise en utilisant son adresse (un pointeur sur cette structure). Noubliez pas, dans ce cas, loprateur (>) pour atteindre les membres de la structure dans la fonction.
eils Cons

ne pas faire Confondre les tableaux et les structures ! faire Utiliser les pointeurs de structures, surtout avec les tableaux de structures. ne pas faire Oublier que lorsque lon incrmente un pointeur, il se dplace dune distance quivalente la taille des donnes pointes. Dans le cas dun pointeur de structure, il sagit de la taille de la structure. faire Utiliser loprateur (>) si vous travaillez avec un pointeur de structure.

Les unions
Unions et structures sont similaires. Une union est dclare et utilise comme une structure, mais on ne peut travailler quavec un seul de ses membres la fois. La raison en est simple, tous les membres dune union sont stocks un par un dans le mme emplacement mmoire.

Dnition, dclaration et initialisation des unions


Les unions sont dnies et dclares de la mme faon que les structures, avec un mot cl diffrent. Linstruction suivante dnit une union simple dune variable char et dune variable integer:
union partage { char c;

http://fribok.blogspot.com/

int i; };

Ce modle dunion, appel partage, va permettre de crer des unions qui pourront contenir soit un caractre c, soit un entier i. Contrairement une structure qui aurait stock les deux valeurs, lunion ne peut en recevoir quune la fois. La Figure 11.7 vous montre comment apparat lunion partage en mmoire.
Figure 11.7 Une union ne peut recevoir quune valeur la fois.
partage.i

partage.c

Lunion peut tre initialise par son instruction de dclaration. Un seul membre pouvant tre utilis la fois, pour viter les erreurs, seul le premier peut tre initialis. Voici un exemple de dclaration et d initialisation dune union de type partage:
union partage variable_generic = {@};

Accder aux membres dune union


On utilise les membres dune union de la mme faon que les membres de structure : avec loprateur (.). Il y a cependant une diffrence importante pour accder aux membres dune union. En effet, celle-ci sauvegarde ses membres la suite les uns des autres, il est donc important dy accder un par un. Examinons lexemple donn dans le Listing 11.6. Listing 11.6 : Exemple de mauvaise utilisation dune union
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: /* Exemple dutilisation de plus dun membre dune union la fois */ #include <stdio.h> #include <stdlib.h> int main() { union shared_tag { charc; inti; longl; floatf; doubled; } shared;

http://fribok.blogspot.com/

Listing 11.6 : Exemple de mauvaise utilisation dune union (suite)


13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: shared.c = $; printf("\nchar c=%c",shared.c); printf("\nint i=%d",shared.i); printf("\nlong l=%ld", shared.l); printf("\nfloat f=%f",shared.f); printf("\ndouble d =%f",shared.d); shared.d = 123456789.8765; printf("\n\nchar c=%c",shared.c); printf("\nint i=%d",shared.i); printf("\nlong l=%ld", shared.l); printf("\nfloat f=%f",shared.f); printf("\ndouble d =%f\n",shared.d); exit(EXIT_SUCCESS); }

Voici le rsultat de lexcution de ce programme :


char c= int i= long l= float f= double d= char c= int i= long l= float f= double d= $ 134513700 134513700 0.000000 0.000000 7 1468107063 1468107063 284852666499072.000000 123456789.876500

Analyse Ce programme dnit et dclare une union appele shared aux lignes 6 12. shared contient cinq membres de types diffrents qui sont initialiss aux lignes 14 et 22. Les lignes 16 20, puis 24 28, de ce programme, prsentent la valeur de chaque membre avec la fonction printf(). lexception de char c = $ et double d =123456789.876500, les rsultats obtenus sur votre machine pourront tre diffrents. La variable c tant initialise en ligne 14, cest la seule valeur utilisable de lunion tant quun autre membre nest pas initialis son tour. Le rsultat de lafchage des autres membres (i, l, f et d) est imprvisible. En ligne 22, une valeur est stocke dans la variable double d. Vous pouvez remarquer que seul le rsultat de lafchage de d est correct. La valeur de c prcdente a t crase par

http://fribok.blogspot.com/

celle de d. Cela met bien en vidence le fait quun seul emplacement mmoire est utilis pour tous les membres de lunion.

Syntaxe du mot cl union


union tag { membre(s); /* instructions ... */ } occurrence;

Le mot cl union annonce la dclaration dune union. Une union regroupe une ou plusieurs variables (membre(s)) sous un nom identique. Tous les membres de cette union occuperont le mme emplacement mmoire. Le mot cl union identie le dbut de la dnition, et il doit tre suivi du nom tag donn au modle de cette union. Ce nom est suivi de la liste des membres entre accolades. Avec occurrence, il est possible de dclarer une union appartenant au modle dni. Si cette instruction ne contient pas de dclaration, cest un simple modle qui sera utilis dans une autre partie du programme pour dclarer des unions. Un modle simple a le format suivant :
union tag { membre(s); /* instructions ... */ };

Voici la syntaxe dune dclaration utilisant ce modle :


union tag occurrence;

Exemple 1
/* Dclaration dun modle dunion appel tag */ union tag { int nbr; char caractre; } /* utilisation du modle */ union tag variable;

Exemple 2
/* Dclaration du modle et dune occurrence de lunion */ union type_generic { char c; int i; float f; double d; } generic;

http://fribok.blogspot.com/

Exemple 3
/* Initialisation dune union */ union date_mod { char date_complte[9]; struct partie_date_mod { char mois[2]; char sparateur1; char jour[2]; char sparateur2; char anne[2]; } partie_date; } date = {"01/04/08"};

Le Listing 11.7 vous montre une utilisation pratique dune union. Cet exemple est trs simple, mais il reprsente lusage le plus courant que lon fait des unions. Listing 11.7 : Utilisation pratique dune union
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: /* Exemple typique dutilisation dune union */ #include <stdio.h> #include <stdlib.h> #define CARACTERE C #define INTEGER I #define FLOAT F struct generic_tag { char type; union shared_tag { char c; int i; float f; } shared; }; void print_fonction(struct generic_tag generic); int main() { struct generic_tag var; var.type = CARACTERE; var.shared.c = $; print_fonction(var); var.type = FLOAT; var.shared.f = (float) 12345.67890; print_fonction(var); var.type = x; var.shared.i = 111;

http://fribok.blogspot.com/

34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:

print_fonction(var); exit(EXIT_SUCCESS); } void print_fonction(struct generic_tag generic) { printf("La valeur gnrique est..."); switch(generic.type) { case CARACTERE: printf("%c", generic.shared.c); break; case INTEGER: printf("%d", generic.shared.i); break; case FLOAT: printf("%f", generic.shared.f); break; default: printf("de type inconnu:%c\n", generic.type); break; } }

La valeur gnrique est...$ La valeur gnrique est...12345.678711 La valeur gnrique est...de type inconnu: x

Analyse Ce programme donne un exemple simplissime de ce que lon peut faire avec une union. Il permet de stocker plusieurs donnes de types diffrents dans le mme emplacement mmoire. Le rle de la structure generic tag est de ranger un caractre, un entier, ou un nombre avec une virgule ottante, dans la mme zone. Cette zone est reprsente par lunion shared qui a le mme principe de fonctionnement que celle du Listing 11.6. Vous pouvez remarquer que la structure generic tag possde un champ supplmentaire appel type. Ce champ est utilis par le programme pour stocker le type de la variable contenue dans shared. Il permet dviter un mauvais usage de shared qui donnerait des valeurs errones comme dans lexemple du Listing 11.6. Les noms des trois constantes CARACTERE, INTEGER et FLOAT, dnies aux lignes 5, 6 et 7, ont t choisis pour faciliter la comprhension du code source. Les lignes 9 16 contiennent la dnition de la structure generic tag, et la ligne 18 prsente le prototype de la fonction print fonction. La structure var est dclare ligne 22 puis initialise pour recevoir un caractre en lignes 24 et 25. Cette valeur est afche avec lappel de la fonction print fonction en ligne 26. Les lignes 28 30, et 32 34 rptent ce processus avec les autres valeurs. La fonction print fonction est le centre du programme. Elle permet dafcher la valeur dune variable de generic tag aprs avoir test le type de cette variable pour viter de faire la mme erreur que dans le Listing 11.6.

http://fribok.blogspot.com/

eils Cons

ne pas faire Essayer dinitialiser plusieurs membres dunion en mme temps. faire Savoir quel membre de lunion est en cours dutilisation. Si vous dnissez un membre dun certain type, et que vous essayez dutiliser un autre type, le rsultat est imprvisible. ne pas faire Oublier que la taille dune union est gale celle du membre le plus grand.

Structures et typedef
Vous pouvez utiliser le mot cl typedef pour crer le synonyme dune structure ou dune union. Les instructions suivantes, par exemple, dnissent coord comme synonyme de la structure dsigne :
typedef struct { int x; int y; } coord;

Vous pourrez ensuite dclarer des structures de ce type en utilisant coord:


coord hautgauche, basdroit;

Attention, le rle de typedef est diffrent de celui du nom dun modle. Si vous crivez :
struct coord { int x; int y; };

coord est le nom du modle. Pour ensuite dclarer une structure il ne faudra pas oublier le mot cl struct:
struct coord hautgauche, basdroit;

En pratique, lun et lautre peuvent tre utiliss indiffremment. typedef donne un code un peu plus concis, mais lutilisation du mot cl struct ne laisse aucun doute sur le type de variable qui a t dclar.

http://fribok.blogspot.com/

Rsum
Nous venons dtudier les structures qui permettent de crer un modle de donnes adapt aux besoins de votre programme. Une structure peut contenir tout type de donne C, y compris des pointeurs, des tableaux ou dautres structures. Chaque donne dune structure, appele membre, est accessible en associant le nom de la structure et le nom du membre avec loprateur (.). Les structures sont utilises individuellement ou en tableaux. Les unions ne prsentent quune diffrence avec les structures : leurs membres sont stocks un par un dans le mme emplacement mmoire. On ne peut donc pas en utiliser plusieurs la fois.

Q&R
Q La dnition dun modle sans dclaration de structure a-t-elle un sens ? R Nous avons tudi deux mthodes pour dclarer une structure. La premire consiste dnir le modle de la structure et de le faire suivre dune occurrence. La seconde consiste dnir le modle seul, puis dclarer, plus loin dans le programme, une structure appartenant ce modle avec le mot cl struct. Cest une pratique courante en programmation. Q Lutilisation de typedef est-elle plus frquente que celle du nom de modle ? R Beaucoup de programmeurs utilisent typedef pour allger leur code source. La plupart des bibliothques de fonctions utilisent beaucoup typedef pour se diffrencier. Cest spcialement vrai pour les bibliothques destines aux bases de donnes. Q Peut-on copier la valeur dune structure dans une autre avec loprateur (=) ? R Oui et non. Les compilateurs rcents permettent dattribuer les valeurs dune structure une autre. Pour les compilateurs plus anciens, il vous faudra attribuer les valeurs membre par membre. La rponse sapplique aussi aux unions. Q Quelle est la taille dune union ? R Un seul emplacement mmoire va recevoir tous les membres de lunion. Sa taille est donc celle du membre le plus encombrant !

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

http://fribok.blogspot.com/

Quiz
1. Quelle est la diffrence entre une structure et un tableau ? 2. Quel est le rle de loprateur (.) ? 3. Quel mot cl faut-il utiliser pour crer une structure ? 4. Quelle est la diffrence entre un nom de modle de structure et un nom de structure ? 5. Que font les quelques lignes de code suivantes ?
struct adresse { char nom[31]; char adr1[31]; char adr2[31]; char ville[11]; char etat[3]; char zip[11]; } monadresse = { "Bradley Jones", "RTSoftware", "P.O. Box 1213", "Carmel", "IN", "460321213"};

6. Supposons que vous ayez dclar un tableau de structures, et que ptr soit un pointeur vers le premier lment de ce tableau (cest--dire vers la premire structure). Comment faut-il faire pour quil pointe sur le second lment ?

Exercices
1. crivez la dnition dune structure appele time, contenant trois membres de type int. 2. crivez le code ralisant les deux tches suivantes : dnition dune structure data contenant un membre de type int et deux membres de type float, et dclaration dune structure info appartenant au type data. 3. Continuez lexercice 2 en attribuant la valeur 100 au membre de type int de la structure info. 4. crivez la dclaration et linitialisation dun pointeur vers info. 5. Trouvez deux mthodes, en utilisant le pointeur de lexercice 4, pour attribuer la valeur 5.5 au premier membre de type float de la structure info. 6. crivez la dnition dune structure appele data qui pourra recevoir une chane de 20 caractres.

http://fribok.blogspot.com/

7. Dnissez une structure contenant ces cinq chanes de caractres : adresse1, adresse2, ville, etat, et zip. Crez un typedef RECORD qui pourra tre utilis pour dclarer des structures appartenant au modle dni. 8. En utilisant le typedef de lexercice prcdent, allouez et initialisez un lment appel monadresse. 9. CHERCHEZ LERREUR :
struct { char signe_zodiaque[21]; int mois; } signe = "lion", 8;

10. CHERCHEZ LERREUR :


/* cration dune union */ union data { char un_mot[4]; long nombre; }variable_generic = {"WOW", 1000};

http://fribok.blogspot.com/

12
La porte des variables
Dans le Chapitre 5, nous avions abord le problme de la porte des variables en diffrenciant celles qui sont dnies dans une fonction de celles qui sont dnies en dehors de la fonction. Aujourdhui, vous allez tudier :

La porte dune variable et les raisons de son importance Les variables externes et les raisons pour lesquelles il vous faudra les viter Les entres/sorties des variables locales La diffrence entre variables statiques et variables automatiques Les variables locales et les blocs Ce qui dtermine le choix dune classe de stockage

http://fribok.blogspot.com/

Dnition de la porte
La notion de porte de la variable fait rfrence aux zones du programme dans lesquelles cette variable est connue, cest--dire aux parties du programme o cette variable est visible ou accessible. Le terme variable utilis tout au long de ce chapitre englobe tous les types de variables du langage C : variables simples, tableaux, structures, pointeurs, etc. Il reprsente aussi les constantes symboliques dnies avec le mot cl const. Le "temps de vie" de la variable, cest--dire le temps pendant lequel la donne est conserve en mmoire, dpend aussi de la porte de la variable.

Exemple
Examinons le programme du Listing 12.1. Il dnit une variable x en ligne 5, utilise printf() pour en afcher la valeur la ligne 11, puis appelle la fonction print value() pour afcher de nouveau la valeur de x. Vous pouvez remarquer que la fonction print value ne reoit pas x en argument, celui-ci est transmis la fonction printf() de la ligne 19. Listing 12.1 : La variable x est accessible depuis la fonction print_value()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 999 999 /* Illustration de la porte dune variable. */ #include <stdio.h> #include <stdlib.h> int x = 999; void print_value(void); int main() { printf("%d\n", x); print_value(); exit(EXIT_SUCCESS); } void print_value(void) { printf("%d\n", x); }

http://fribok.blogspot.com/

Analyse La compilation et lexcution de ce programme ne posent aucun problme. Modions-le pour que la dnition de la variable x se retrouve dans la fonction main(). Le Listing 12.2 prsente le programme modi. Listing 12.2 : La variable x nest pas accessible par la fonction print_value
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: /* Dmonstration de la porte dune variable. */ #include <stdio.h> #include <stdlib.h> void print_value(void); int main() { int x = 999; printf("%d", x); print_value(); exit(EXIT_SUCCESS); } void print_value(void) { printf("%d\n", x); }

Analyse Si vous essayez de compiler ce programme, vous recevrez un message derreur similaire celui-ci :
Errorlist12_2.c19: undefined symbol x in function print_value

Le nombre qui suit le nom du chier est le numro de la ligne do vient lerreur. La ligne 19 contient lappel la fonction printf() dans la fonction print value(). Ce message vous indique que, dans la fonction print value, la variable x nest pas dnie. En dautres termes, elle nest pas accessible. Vous pouvez remarquer que lappel de la fonction printf() la ligne 11 na pas gnr de message derreur, car la variable x est visible dans cette partie du programme. Lunique diffrence entre le Listing 12.1 et le Listing 12.2 est lemplacement de la dnition de x. Cet emplacement dtermine sa porte. Dans le Listing 12.1, x est une variable externe dont la porte stend tout le programme. Les deux fonctions main() et print value() y ont accs. Dans le Listing 12.2, x est une variable locale dont la porte

http://fribok.blogspot.com/

est limite au seul bloc main(). Pour la fonction print value(), la variable x nexiste pas.

Importance de la notion de porte


Limportance de la notion de porte est lie au principe de la programmation structure que nous avons tudie au Chapitre 5. Cette mthode de programmation consiste diviser le programme en fonctions indpendantes, chacune de ces fonctions ralisant une tche spcique. Le mot cl de cette dnition est indpendance. Pour que cette indpendance soit relle, la fonction doit possder ses propres variables, sans possibilit dinterfrences avec le reste du programme. La meilleure faon dobtenir dune fonction un rsultat able est den isoler les donnes. Toutefois, dans certains cas, une isolation complte des donnes nest pas souhaitable. Vous apprendrez vite, en tant que programmeur, jouer sur la porte des variables pour contrler le niveau "disolement" de vos donnes.

Les variables externes


Une variable externe est dnie en dehors de toute fonction, y compris de la fonction principale main(). La plupart des exemples que nous avons dj tudis utilisaient des variables externes dnies au dbut du code source, avant la premire excution de main(). Les variables externes sont aussi appeles variables globales. Si vous ninitialisez pas une telle variable lors de sa dnition, le compilateur le fait de faon implicite avec la valeur 0.

Porte des variables externes


La porte dune variable externe stend au programme tout entier. Elle peut donc tre utilise par la fonction main() ou toute autre fonction du programme. Il existe cependant une restriction. Cette dnition nest vraie que si le code source de votre programme est sauvegard dans un chier unique. Vous apprendrez, au Chapitre 21, quun programme peut tre divis dans plusieurs chiers. Il faudra prendre, dans ce cas, des mesures particulires pour les variables externes.

Quand utiliser les variables externes


Les variables externes sont rarement utilises, car elles vont lencontre des principes dindpendance de la programmation structure entre les diffrents blocs du programme. Chaque bloc ou fonction doit contenir le code et les donnes ncessaires lexcution de la tche qui lui est cone.

http://fribok.blogspot.com/

Vous pouvez utiliser une variable externe quand la plupart des fonctions du programme ont besoin daccder une mme donne. Les constantes symboliques dnies avec le mot cl const sont souvent utilises de cette faon. Si la donne ne doit tre connue que dun petit nombre de fonctions, il est prfrable de la passer en argument.

Le mot cl extern
Quand une fonction utilise une variable externe, il est bon de dclarer cette variable dans la fonction avec le mot cl extern:
extern type nom;

type reprsente le type de la variable dont il prcde le nom. Nous pouvons transformer, par exemple, le Listing 12.1 en ajoutant la dclaration de x dans les fonctions main() et print value(). Le programme source obtenu est prsent dans le Listing 12.3. Listing 12.3 : Dclaration en extern de la variable x dans les fonctions main() et print_value()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 999 999 /* Exemple de dclaration de variables externes. */ #include <stdio.h> #include <stdlib.h> int x = 999; void print_value(void);

int main() { extern int x; printf("%d\n", x); print_value(); exit(EXIT_SUCCESS); } void print_value(void) { extern int x; printf("%d\n", x); }

http://fribok.blogspot.com/

Analyse Ce programme afche deux fois la valeur de x: dabord en ligne 13 partir de la fonction main(), puis en ligne 22 dans la fonction print value(). La variable x est dnie ligne 5 avec le type int et initialise avec la valeur 999. Cette variable est dclare en lignes 11 et 21 avec le type extern int. Il faut distinguer la dnition de la variable, qui rserve un emplacement mmoire pour cette variable, et la dclaration extern. Cette dernire signie : "cette fonction utilise la variable externe de tel type, et de tel nom, qui est dnie dans une autre partie du programme". Dans notre exemple, la dclaration de la ligne 21 nest pas indispensable. Toutefois, si la fonction print value stait trouve dans un bloc de code diffrent de celui de la dclaration globale de la ligne 5, cette dclaration extern aurait t obligatoire.

Les variables locales


Une variable locale est une variable dnie dans une fonction, et sa porte se limite la fonction dans laquelle elle est dnie. Nous avons tudi ces variables dans le Chapitre 5. Contrairement aux variables globales, celles-ci ne sont pas initialises par le compilateur lorsque vous omettez de le faire. Une variable locale qui na pas t initialise contient une valeur indtermine. La variable x du Listing 12.2 est une variable locale pour la fonction main(). faire Utiliser des variables locales pour les compteurs de boucle. Utiliser des variables locales pour isoler les valeurs quelles contiennent du reste du programme. ne pas faire Utiliser des variables externes si elles ne sont pas utilises par la majorit des fonctions du programme.

eils Cons

Variables statiques et automatiques


Par dfaut, les variables locales sont automatiques. Cela signie quelles sont cres et dtruites avec lappel et la n de la fonction. En dautres termes, la valeur de cette variable nest pas conserve entre deux appels de la fonction dans laquelle elle est dnie.

http://fribok.blogspot.com/

Si la dernire valeur de la variable locale doit tre connue lappel de la fonction, la variable doit tre dnie avec le mot cl static. Une fonction dimpression, par exemple, doit connatre le nombre de lignes dj envoyes vers limprimante pour effectuer correctement le changement de page. Voici un exemple de dnition dune variable statique :
void fonc1(int x) { static int a; .../*Instructions */ }

Le Listing 12.4 illustre la diffrence entre variables locales statiques et variables locales automatiques. Listing 12.4 : Diffrence entre variables statiques et variables automatiques
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: /* Exemple de variables locales statiques et automatiques. */ #include <stdio.h> #include <stdlib.h> void func1(void); int main() { int count; for (count = 0; count < 20; count++) { printf("Iteration n%d: ", count); func1(); } exit(EXIT_SUCCESS); } void func1(void) { static int x = 0; int y = 0; printf("x =%d, y =%d\n", x++, y++); } n n n n n n 0: 1: 2: 3: 4: 5: x x x x x x = = = = = = 0, 1, 2, 3, 4, 5, y y y y y y = = = = = = 0 0 0 0 0 0

Iteration Iteration Iteration Iteration Iteration Iteration

http://fribok.blogspot.com/

Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration Iteration

n n n n n n n n n n n n n n

6: x = 6, y 7: x = 7, y 8: x = 8, y 9: x = 9, y 10: x = 10, 11: x = 11, 12: x = 12, 13: x = 13, 14: x = 14, 15: x = 15, 16: x = 16, 17: x = 17, 18: x = 18, 19: x = 19,

= = = = y y y y y y y y y y

0 0 0 0 = = = = = = = = = =

0 0 0 0 0 0 0 0 0 0

Analyse Ce programme contient la fonction func1() qui dnit et initialise une variable de chaque type (lignes 20 26). chaque appel de la fonction, les variables sont afches et incrmentes (ligne 25). La fonction principale main() (lignes 7 18) contient une boucle for (lignes11 15), qui envoie un message lcran (ligne 13) et appelle la fonction func1() (ligne 14). Cette boucle sexcute 20 fois. Le rsultat de lexcution du programme vous montre que la valeur de la variable statique x augmente chaque excution de la boucle, car la valeur est conserve entre deux appels. La variable automatique y, au contraire, est initialise 0 chaque appel de la fonction. Ce programme illustre aussi la diffrence de traitement des deux initialisations dune variable (lignes 22 et 23). La variable statique nest initialise quau premier appel de la fonction. Quand la fonction est de nouveau appele, le programme se souvient que cette variable a dj t initialise ; il ne va donc pas recommencer lopration. La variable gardera ainsi sa valeur antrieure. La variable automatique, au contraire, est initialise chaque appel de la fonction. Automatique tant le type par dfaut pour une variable locale, il nest pas ncessaire de lindiquer dans la dnition. Vous pouvez tout de mme inclure le mot cl auto de cette faon :
void func1(int y) { auto int count; /* instructions ... */ }

http://fribok.blogspot.com/

La porte des paramtres dune fonction


Les variables de la liste des paramtres dune fonction ont une porte locale. tudions lexemple suivant :
void func1(int x) { int y; /* instructions ... */ }

x et y sont des variables locales pour la fonction func1(). La valeur initiale de x dpend de la valeur transmise par le programme appelant. Quand la fonction a utilis cette valeur, x peut tre traite comme nimporte quelle variable locale. Les variables paramtres tant toujours initialises avec la valeur passe en argument par le programme appelant, les termes statique ou automatique nont pas de sens en ce qui les concerne.

Les variables statiques externes


On peut donner le type statique une variable externe en ajoutant le mot cl static dans sa dnition :
static float taux; int main() { /* instructions ... */ }

La diffrence entre une variable externe et une variable externe statique concerne la porte de ces variables. Une variable externe statique est visible par toutes les fonctions du chier dans lequel elle se trouve. Une variable externe simple est visible par toutes les fonctions du chier et peut tre utilise par des fonctions dans dautres chiers. La rpartition dun code source dans des chiers distincts est traite dans le Chapitre 21.

Variables de type register


Le mot cl register est utilis pour demander au compilateur de stocker une variable locale automatique dans un registre plutt que dans un emplacement de la mmoire standard. Le processeur central (CPU) de votre ordinateur contient quelques emplacements mmoire appels registres. Ces registres sont utiliss pour des oprations comme laddition ou la division. La CPU prend les donnes en mmoire, les copie dans les registres,

http://fribok.blogspot.com/

ralise lopration demande, puis les replace en mmoire. Si une variable est enregistre directement dans un registre, les oprations qui la concernent seront effectues plus rapidement. Exemple :
void func1(void) { register int x; /* instructions ... */ }

Le mot cl register effectue une demande au compilateur, et non un ordre. En fonction des besoins du programme, le registre pourra ne pas tre disponible pour la variable. Dans ce cas, le compilateur traitera la variable comme une variable automatique ordinaire. Le type de stockage register doit tre choisi pour les variables souvent utilises par la fonction, pour un compteur de boucle par exemple. Le mot cl register ne sapplique quaux variables numriques simples. On ne peut pas lutiliser avec les tableaux ou les structures. De mme, il ne peut tre utilis avec les classes de stockage externe ou statique, et vous ne pouvez pas dnir un pointeur vers une variable de type register. Enn, et cest peut-tre le point le plus important, le mot cl register ne devrait plus tre utilis pour les variables de programmes destins tre utiliss sur les machines puissantes daujourdhui. En effet, les processeurs sont devenus complexes et il vaut mieux faire conance aux compilateurs qui savent mieux optimiser que la plupart des programmeurs. faire Initialiser les variables locales pour tre sr de la valeur quelles contiennent. Initialiser les variables globales, mme si elles le sont par dfaut. En prenant lhabitude de toujours initialiser vos variables, vous viterez des erreurs. Transmettre les donnes en tant que paramtres dune fonction plutt que les dclarer comme variables globales si elles ne sont utilises que par quelques fonctions. ne pas faire Utiliser le type de variable register pour des valeurs non numriques, des structures ou des tableaux.

eils Cons

http://fribok.blogspot.com/

Les variables locales et la fonction main()


La fonction main() est appele quand le programme commence son excution, et rend le contrle au systme dexploitation quand le programme est termin. Cela signie quune variable locale dnie dans main() est cre quand le programme commence, et quelle cesse dexister quand le programme se termine. Pour cette fonction, la notion de variable locale statique na donc aucun sens. Une variable ne peut subsister entre deux excutions du programme. Il ny a donc aucune diffrence pour la fonction main() entre une variable locale statique et une variable locale automatique.

Choix de la classe de stockage


Le Tableau 12.1 prsente les cinq classes de stockage disponibles en C. Il vous aidera faire votre choix.
Tableau 12.1 : Les cinq classes de stockage pour les variables du langage C

Classe de stockage
Automatique Statique Registre Externe Externe

Mot cl
Aucun 1 static register Aucun 2 static

Dure de vie
Temporaire Temporaire Temporaire Permanent Permanent

Dnition
Dans la fonction Dans la fonction Dans la fonction Hors de la fonction Hors de la fonction

Porte
Locale Locale Locale Globale (tous les chiers) Globale (un chier)

1. Le mot cl auto est en option 2. Le mot cl extern est utilis dans les fonctions pour dclarer une variable externe statique qui est dnie ailleurs dans le programme.

Quand vous choisissez votre classe de stockage, prfrez une classe automatique chaque fois que cest possible, et utilisez les autres seulement quand cest ncessaire. Voici quelques rgles pour vous guider :

Commencez en donnant une classe de stockage locale automatique chaque variable. Pour toutes les fonctions, sauf main(), choisissez la classe statique quand la valeur de la variable doit tre conserve entre deux appels. Si la variable est utilise par toutes ou presque toutes les fonctions, dnissez-la avec la classe externe.

http://fribok.blogspot.com/

Variables locales et blocs


Nous navons parl que de variables locales pour une fonction, mais vous pouvez dnir des variables locales pour un bloc du programme (portion de code entour par des accolades). Le Listing 12.5 vous en prsente un exemple. Listing 12.5 : Dnition de variables locales dans un bloc du programme
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: /* Exemple de variable locale dans un bloc. */ #include <stdio.h> #include <stdlib.h> int main() { /* Dfinition dune variable locale pour main(). */ int count = 0; printf("Hors du bloc, count =%d\n", count);

/* Dbut dun bloc. */ { /* Dfinition dune variable locale pour le bloc. */ int count = 999; printf("Dans le bloc, count =%d\n", count); } printf("De nouveau hors du bloc, count =%d\n", count); exit(EXIT_SUCCESS); }

Hors du bloc, count = 0 Dans le bloc, count = 999 De nouveau hors du bloc, count = 0

Analyse Ce programme vous dmontre que la variable count dans le bloc est indpendante de la variable count dnie en dehors du bloc. La ligne 9 dnit la variable count de type int et linitialise 0. La porte de cette variable est la fonction main(). La ligne 11 afche la valeur dinitialisation de la variable (0). Les lignes 14 19 reprsentent un bloc dans lequel une autre variable count est dnie avec le type int. La ligne 18 afche la valeur dinitialisation de cette variable : 999. Linstruction printf() de la ligne 21 se trouvant aprs la n du bloc (ligne 19) ; elle utilise la variable count initiale (dclare en ligne 9) de la fonction main().

http://fribok.blogspot.com/

Lemploi de ce type de variable locale nest pas courant en programmation C. Son utilit est de permettre un programmeur disoler un problme dans un programme. Il suft de dcouper le code en blocs avec des accolades, et dintroduire des variables locales pour trouver lerreur. faire Positionner des variables en dbut de bloc (temporairement) pour identier un problme. ne pas faire Placer une dnition de variable dans un programme ailleurs quen dbut de fonction ou de bloc (contrairement au C++).

eils Cons

Rsum
Ltude de ce chapitre vous a fait dcouvrir les classes de stockage des variables du langage C. Toute variable C, de la variable simple aux structures en passant par les tableaux, a une classe de stockage spcique. Cette classe dtermine deux caractristiques : la porte, ou de quelle partie du programme la variable est visible, et la dure de vie de la variable en mmoire. Le choix de la classe de stockage est un aspect important de la programmation structure. En utilisant dans les fonctions un maximum de variables locales, vous rendez ces fonctions indpendantes les unes des autres. Une variable doit appartenir une classe de stockage automatique, sauf sil existe une raison particulire de la rendre externe ou statique.

Q&R
Q Pourquoi ne pas toujours utiliser des variables globales puisquelles peuvent tre utilises nimporte o dans le programme ? R Quand vos programmes commenceront atteindre une taille respectable, ils contiendront de plus en plus de dclarations de variables. La mmoire disponible sur votre machine nest pas illimite. Les variables globales occupent une place en mmoire pendant toute la dure dexcution du programme, alors que les variables locales noccupent un emplacement mmoire que pendant la dure dexcution de leur fonction. (Une variable statique conserve son emplacement mmoire depuis sa premire

http://fribok.blogspot.com/

utilisation jusqu la n de lexcution du programme.) De plus, la valeur dune variable globale peut tre altre accidentellement par une des fonctions. Elle ne contiendra donc plus la bonne valeur quand vous en aurez besoin. Q Nous avons vu, au Chapitre 11, que la porte inuence une structure, mais pas son modle. Pourquoi ? R Quand vous dclarez une structure sans occurrences, vous crez un modle ; il ny a pas de dclaration de variable. Cest la raison pour laquelle le modle peut se situer en dehors de toute fonction sans effet rel sur la mmoire. Beaucoup de programmeurs sauvegardent leurs modles de structures dans les chiers en-tte. Il ne leur reste plus qu inclure ce chier quand il leur faut crer une structure appartenant un des modles. (Les chiers en-tte sont traits dans le Chapitre 21.) Q Comment lordinateur fait-il la diffrence entre une variable globale et une variable locale qui auraient le mme nom ? R Quand une variable locale est dclare avec le mme nom quune variable globale, cette dernire est ignore temporairement par le programme (jusqu ce que la variable locale ne soit plus visible).

Atelier
Cet atelier comporte un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

Quiz
1. Quest-ce que la porte ? 2. Quelle est la principale diffrence entre une classe de stockage locale et une classe de stockage externe ? 3. En quoi lemplacement de la dnition dune variable affecte-t-il la classe de stockage ? 4. Lorsquon dnit une variable locale, quelles sont les deux options qui concernent la dure de vie de cette variable ? 5. Quand elles ont t dnies, votre programme peut initialiser des variables locales statiques et automatiques. Quand doit-on faire ces initialisations ? 6. Vrai ou faux : une variable de type register sera toujours stocke dans un registre.

http://fribok.blogspot.com/

7. Quelle est la valeur contenue dans une variable globale qui na pas t initialise ? 8. Quelle est la valeur contenue dans une variable locale qui na pas t initialise ? 9. Quel sera le message afch par la ligne 21 du Listing 12.5 si les lignes 9 et 11 sont supprimes ? 10. Comment doit-on dclarer une variable locale de type int pour que sa valeur soit conserve entre deux appels de la fonction qui lutilise ? 11. quoi sert le mot cl extern? 12. quoi sert le mot cl static?

Exercices
1. Corrigez lerreur du Listing 12.2 sans utiliser de variable externe. 2. crivez un programme qui dclare une variable globale var de type int. Initialisez cette valeur puis afchez son contenu en utilisant une fonction autre que main(). Est-il ncessaire de transmettre var dans la liste des paramtres de la fonction ? 3. Transformez le programme de lexercice 3 pour que la variable var soit une variable locale de la fonction main(). Est-il maintenant ncessaire de transmettre var dans la liste des paramtres de la fonction ? 4. Un programme peut-il avoir une variable locale et une variable globale du mme nom ? crivez un programme pour justier votre rponse. 5. CHERCHEZ LERREUR : Pourrez-vous trouver le problme de ce code ? (Conseil : lerreur vient de lendroit o une variable est dclare.)
void exemple_de_fonction(void) { int ctr1; for (ctr1 = 0; ctr1 < 25; ctr1++) printf("*"); puts ("Cela est un exemple de fonction\n"); { char star = *; puts( "il y a un problme\n" ); for (int ctr2 = 0; ctr2 < 25; ctr2++) { printf("%c", star); } } }

http://fribok.blogspot.com/

6. CHERCHEZ LERREUR :
#include <stdio.h> #include <stdlib.h> int main() { int x = 1; static int tally = 0; for (x = 0; x < 101; x++) { if (x% 2 == 0)/*si x est pair */ tally++;../* on ajoute 1 tally. */ } printf("Il y a%d nombres pairs.\n", tally); exit(EXIT_SUCCESS); }

7. CHERCHEZ LERREUR :
#include <stdio.h> #include <stdlib.h> void print_fonction(char star); int ctr; int main() { char star; print_fonction(star); exit(EXIT_SUCCESS); } void print_fonction (char star) { char dash; for (ctr = 0; ctr < 25; ctr++) { printf("%c%c", star, dash); } }

8. Quafche le programme suivant ?


#include <stdio.h> #include <stdlib.h> void print_letter2(void);/* Dclaration de la fonction */ int ctr; char letter1 = X; char letter2 = =; int main() { for(ctr = 0; ctr < 10; ctr++) {

http://fribok.blogspot.com/

printf("%c", letter1); print_letter2(); } exit(EXIT_SUCCESS); } void print_letter2(void) { for(ctr = 0; ctr < 2; ctr++) printf("%c", letter2); }

9. CHERCHEZ LERREUR : Le programme prcdent peut-il tre excut ? Si la rponse est non, quel est le problme ? Corrigez-le.

http://fribok.blogspot.com/

Exemple pratique 4

Les messages secrets


Voici la quatrime section de ce type. Le programme quelle prsente comprend de nombreux lments tudis prcdemment, et en particulier les chiers disques traits au Chapitre 16. Le programme qui suit permet de coder ou de dcoder des messages. Pour lexcuter, vous devrez fournir deux paramtres :
coder nomfichier action

nomfichier reprsente soit le nom du chier crer pour enregistrer le message secret, soit le nom du chier qui contient le message dcoder. Laction sera D pour dcoder ou C pour coder un message. Si vous lancez le programme sans lui transmettre de paramtre, il afchera les instructions pour taper correctement la commande. En transmettant ce programme des amis ou connaissances, vous pourrez leur envoyer des messages cods. Ceux-ci ne pourront tre lus que par lintermdiaire du programme ! Listing Exemple pratique 4 : coder.c
1: /* Programme: coder.c 2: * Syntaxe : coder [nomfichier] [action] 3: * nomfichier est le nom du fichier pour les donnes codes 4: * action est gal D pour dcoder, ou nimporte quel 5: * autre caractre pour coder 6: *---------------------------------------------------------------*/ 7: 8: #include <stdio.h> 9: #include <stdlib.h>

http://fribok.blogspot.com/

10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:

#include <string.h> int encode_character( int ch, int val ); int decode_character( int ch, int val ); int main( int argc, char *argv[]) { FILE *fh; /* Descripteur du fichier */ int rv = 1; /* valeur renvoye */ int ch = 0; /* variable pour stocker un caractre */ unsigned int ctr = 0; /* compteur */ int val = 5; /* valeur pour coder avec */ char buffer[257]; /* le buffer */ if( argc!= 3 ) { printf("\nErreur: nombre de paramtres incorrect..." ); printf("\n\nSyntaxe:\n %s nomfichier action", argv[0]); printf("\n\n O:"); printf("\n nomfichier = nom du fichier coder "); printf("ou dcoder"); printf("\n action = D pour dcoder ouC pour coder\n\n") ; rv = -1; /* valeur de lerreur renvoye */ } else if(( argv[2][0] == D) || (argv[2][0] == d )) /* dcodage */ { fh = fopen(argv[1], "r"); /* ouverture du fichier */ if( fh <= 0 ) /* contrle */ { printf( "\n\nErreur douverture du fichier..." ); rv = -2; /* valeur de lerreur renvoye */ } else { ch = getc( fh ); /* lecture dun caractre */ while(!feof( fh ) ) /* Fin du fichier? */ { ch = decode_character( ch, val ); putchar(ch); /* Affichage du caractre */ ch = getc( fh); } fclose(fh); printf( "\n\nFichier dcod et affich.\n" ); } } else { /* Codage dans un fichier. */ fh = fopen(argv[1], "w"); if( fh <= 0 ) { printf( "\n\nErreur pendant la cration du fichier..." ); rv = -3; /* Valeur renvoye */ }

http://fribok.blogspot.com/

65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99:

else { printf("\n\nEntrez le texte coder. "); printf("Entrez une lignevide pour terminer.\n\n"); while( fgets(buffer, sizeof(buffer), stdin)) { if((buffer[0] == 0) || (buffer[0] == \n)) break; for( ctr = 0; ctr < strlen(buffer); ctr++ ) { ch = encode_character( buffer[ctr], val ); ch = fputc(ch, fh); /* Ecriture du fichier */ } } printf( "\n\nMessage cod et enregistr.\n" ); fclose(fh); } } exit((rv==1)?EXIT_SUCCESS:EXIT_FAILURE); } int encode_character( int ch, int val ) { ch = ch+val; return (ch); } int decode_character( int ch, int val ) { ch = ch - val; return (ch); }

Voici un exemple de message secret :


hjhn%jxy%zs%rjxxflj%hti

Il signie :
Ceci est un message cod

Analyse Le programme code et dcode simplement en ajoutant ou en soustrayant une valeur aux caractres. Le code obtenu sera bien sr trs facile dchiffrer. Vous pouvez compliquer un peu ce chiffrage en remplaant les lignes 91 et 97 par la ligne suivante :
ch = ch ^ val;

http://fribok.blogspot.com/

Loprateur binaire mathmatique ^ modie les bits du caractre. Le codage obtenu sera plus difcilement dchiffr. Si vous envisagez de distribuer ce programme plusieurs personnes diffrentes, vous pourriez ajouter un troisime paramtre pour dnir val. Cette variable contient la valeur utilise pour le codage ou le dcodage.
ntion Atte

Ce programme est loin dtre blind (par exemple val doit tre infrieur 13, valeur du code ASCII du retour la ligne). Lalgorithme utilis est de plus extrmement simple et ne rsistera pas longtemps une personne malveillante ou trop curieuse. Si vous avez un rel besoin de chiffrer vos donnes, orientezvous plutt vers un logiciel du march tel que le logiciel libre gpg. Sachez galement que le chiffrage de donnes est soumis la lgislation en vigueur.

http://fribok.blogspot.com/

13
Les instructions de contrle (suite)
Le Chapitre 6 a introduit quelques-unes des instructions de contrle du langage C. Ces instructions permettent de contrler lexcution des autres instructions du programme. Ce chapitre couvre dautres aspects du contrle des programmes, comme linstruction goto, et quelques exemples intressant de ce que lon peut faire avec une boucle. Aujourdhui, vous allez tudier :

Les instructions break et continue La dnition et lintrt des boucles continues Le fonctionnement de goto Linstruction switch Les diffrentes manires de sortir du programme Lexcution automatique de fonctions une fois le programme termin Lintroduction de commandes systme dans votre programme

http://fribok.blogspot.com/

Fin de boucle prmature


Nous avons tudi, au Chapitre 6, les trois instructions de boucle for, while et do while. Ces boucles permettent dexcuter un bloc dinstructions de zro n fois, en fonction de conditions tablies dans le programme. Dans tous les cas, la sortie de la boucle nintervient que lorsquune certaine condition est remplie. Les deux instructions que nous allons maintenant tudier, break et continue, permettront dexercer un contrle supplmentaire sur lexcution de ces trois boucles.

Linstruction break
Cette instruction se place exclusivement dans le corps dune boucle for, while ou do while (ou avec linstruction switch tudie en n de chapitre). Quand une instruction break est rencontre en cours dexcution du programme, la sortie de la boucle est immdiate. Exemple :
for (count = 0; count < 10; count++) { if (count == 5) break; }

La premire instruction est celle dune boucle qui doit sexcuter 10 fois. Pourtant, la sixime itration, la variable count est gale 5 et linstruction break sexcute provoquant la n de la boucle for. Lexcution se poursuit avec la premire instruction qui suit laccolade de n de la boucle. Quand cette instruction break se trouve dans une boucle imbrique, lexcution se poursuit avec la suite de la premire boucle. Listing 13.1 : Utilisation de linstruction break
1: /* Exemple dutilisation de linstruction break. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: char s[] = "Cela est une chane de test. Elle contient deux \ 6: phrases."; 7: int main() 8: { 9: int count; 10: 11: printf("Chane initiale: %s\n", s); 12: 13: for (count = 0; s[count]!=\0; count++) 14 : { 15: if (s[count] == .) 16: {

http://fribok.blogspot.com/

17: 18: 19: 20: 21: 22: 23: 24:

s[count+1] = \0; break; } } printf("Chane modifie: %s\n", s); exit(EXIT_SUCCESS); }

Chane initiale: Cela est une chane de test. Elle contient deux phrases. Chane modifie: Cela est une chane de test.

Analyse Ce programme extrait la premire phrase dune chane de caractres. La boucle for (lignes 13 20) analyse la chane, caractre par caractre, pour trouver le premier point. La variable count est initialise et incrmente chaque excution de la boucle pour se positionner sur le caractre suivant de la chane s. La ligne 15 vrie si le caractre point est un point. Si cest le cas, la ligne 17 ajoute le caractre de n de chane immdiatement aprs le point. La chane initiale tant ainsi tronque, il nest plus ncessaire de poursuivre lexcution la boucle, qui est alors interrompue par linstruction break. Lexcution du programme se poursuit en ligne 21. Si la boucle ne trouve pas de point, la chane reste inchange. Une boucle peut contenir plusieurs instructions break, mais seule la premire rencontre sera excute. Si aucune instruction break nest excute, la boucle se termine normalement. La Figure 13.1 vous montre le mcanisme de cette instruction.
Figure 13.1 Les instructions break et continue.

while ( . . . ) { ... continue; ... break; ... ... }

Syntaxe de linstruction break


break;

Elle est utilise lintrieur dune boucle ou dune instruction switch. Elle provoque larrt de la boucle ou de linstruction switch en cours, et donne le contrle linstruction situe aprs la n de cette boucle ou de cette instruction switch.

http://fribok.blogspot.com/

Exemple
int x; printf("comptons de 1 10\n"); /* La boucle ne contient pas de condition! */ for (x = 1;; x++) { if (x == 10)/* recherche de la valeur 10 */ break;/* fin de la boucle */ printf("\n%d", x); }

Linstruction continue
Comme linstruction break, continue ne peut tre place que dans le corps dune boucle for, while, ou do while. Lexcution dune instruction continue arrte le processus de bouclage, et lexcution recommence en dbut de boucle. La Figure 13.1 donne le schma de fonctionnement de cette instruction. Le Listing 13.2 utilise linstruction continue. Il lit une ligne de texte entre au clavier pour lafcher ensuite sans ses voyelles. Listing 13.2 : Utilisation de linstruction continue
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: /* Exemple dutilisation de linstruction continue. */ #include <stdio.h> #include <stdlib.h> int main() { /* Dclaration dune mmoire tampon pour les donnes entres, */ /* et dun compteur. */ char buffer[81]; int ctr; /* Lecture dune lignede texte. */ puts("Entrez une lignede texte: "); lire_clavier(buffer, sizeof(buffer)); /* On se dplace dans la chane en affichant tous les */ /* caractres qui ne sont pas des voyelles minuscules. */ for (ctr = 0; buffer[ctr]!=\0; ctr++) { /* Si le caractre est une voyelle minuscule, */ /* il nest pas affich. */ if (buffer[ctr] == a || buffer[ctr] == e

http://fribok.blogspot.com/

26: 27: 28: 29: 30: 31: 32: 33: 34: 35:

|| buffer[ctr] == i || buffer[ctr] == o || buffer[ctr] == u) continue; /* Si ce nest pas une voyelle, on laffiche. */

putchar(buffer[ctr]); } exit(EXIT_SUCCESS); }

Entrez une lignede texte: Cela est une ligne texte Cl st n lgn d txt

Analyse Ce programme na pas beaucoup dintrt pratique, mais il utilise une instruction conti nue. Les variables sont dclares en lignes 9 et 10. Le tableau buffer[] stocke la ligne de texte lue en ligne 15. La variable ctr permet de se dplacer dun lment lautre de buffer[], pendant que la boucle for (lignes 20 32) cherche les voyelles. Pour cela, linstruction if (lignes 25 27) compare chaque lettre de la chane avec les cinq voyelles minuscules. Si la lettre correspond une voyelle, linstruction continue est excute et le contrle est donn la ligne 20 du programme. Si la lettre nest pas une voyelle, lexcution se poursuit avec linstruction if de la ligne 31. putchar() est une fonction de la bibliothque qui permet dafcher un caractre lcran.

Syntaxe de linstruction continue


continue;

Linstruction continue doit tre utilise dans une boucle. Elle provoque lexcution immdiate de la prochaine itration de la boucle. Les instructions situes entre continue et la n de la boucle sont ignores. Exemple
int x; printf("On naffiche que les nombres pairs entre 1 et 10\n"); for(x = 1; x<= 10; x++) { if(x% 2!= 0)/* contrle de la parit */ continue;/* on rcupre la prochaine occurrence de x */ printf("\n%d", x);

http://fribok.blogspot.com/

Linstruction goto
Cette instruction fait partie des instructions du langage C qui excutent un saut inconditionnel ou un branchement. Rencontre au cours de lexcution dun programme, une instruction goto provoque le transfert ou le branchement immdiat vers lemplacement dsign. Ce branchement est dit inconditionnel, car il ne dpend daucune condition. Linstruction goto et son tiquette peuvent se trouver dans des blocs de code diffrents, mais doivent toujours faire partie de la mme fonction. Le Listing 13.3 prsente un programme simple utilisant goto. Listing 13.3 : Utilisation de linstruction goto
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: /* Illustration de linstruction goto */ #include <stdio.h> #include <stdlib.h> int main() { int n; start:; puts("Entrez un nombre entre 0 et 10: "); scanf("%d", &n); if (n < 0 || n > 10) goto start; else if (n == 0) goto localisation0; else if (n == 1) goto localisation1; else goto localisation2; localisation0:; puts("Vous avez tap 0.\n"); goto end; localisation1:; puts("Vous avez tap 1.\n"); goto end; localisation2:; puts("Vous avez tap quelque chose entre 2 et 10.\n"); end:; return 0;

http://fribok.blogspot.com/

37: } Entrez un nombre entre 0 et 10: 9 Vous avez tap quelque chose entre 2 et 10.

eils Cons

faire Utiliser goto bon escient, en particulier pour se brancher sur des instructions de traitement derreur lorsquune erreur est survenue. Utiliser des boucles (while, for...), break ou continue lorsquon peut viter dutiliser goto. ne pas faire Confondre break et continue: la premire termine une boucle prmaturment, alors que la seconde relance la boucle pour litration suivante. Utiliser goto tort et travers.

Analyse Ce programme simple lit un nombre compris entre 0 et 10. Si lutilisateur entre un nombre nappartenant pas cet intervalle de valeurs, linstruction goto de la ligne 15 donne le contrle du programme la ligne 9. Cette ligne est celle de ltiquette start. Si le nombre lu est bien compris entre 0 et 10, la ligne 16 compare sa valeur avec 0. Si sa valeur est gale 0, linstruction goto de la ligne 17 donne le contrle la ligne 23 (localisation0). Un message est alors envoy lutilisateur (ligne 24) et une autre instruction goto est excute. Cette dernire instruction se branche sur ltiquette end qui est la n du programme. Le programme suit la mme logique pour les autres chiffres. Ltiquette associe linstruction goto peut se situer avant ou aprs cette instruction dans le code, lessentiel tant quelles soient toutes les deux dans la mme fonction. Elles peuvent se trouver dans des blocs diffrents : vous pouvez coder, par exemple, un transfert de lintrieur dune boucle vers lextrieur au moyen dune instruction for. Toutefois, nous vous recommandons fortement de ne jamais utiliser goto dans vos programmes. Voici pourquoi :

Vous navez pas besoin de goto. Toutes les tches que vous aurez programmer peuvent tre ralises avec les autres instructions de branchement du langage C. Cest dangereux. Quand un programme excute un branchement aprs une instruction goto, il ne garde aucune trace de lemplacement do il vient et lordre dexcution va vite se compliquer. Cest ce que lon appelle le code spaghetti.

http://fribok.blogspot.com/

Syntaxe de linstruction goto


goto identifiant;

Lidentiant est une instruction label qui identie un emplacement du programme pour la suite de lexcution. Une instruction label est constitue dun identiant suivi de deux points, puis dune instruction C :
identifiant: instructionC ;

Si vous ne voulez indiquer que le label, vous pouvez le faire suivre de linstruction nulle :
localisation1:;

Les boucles innies


Une boucle innie est une boucle for, while ou do while, qui bouclerait toujours si on ne lui ajoutait pas des instructions. En voici un exemple :
while (1) { /* instructions... */ }

La condition que teste while est la constante 1, qui sera toujours vraie et ne pourra pas tre change par le programme. Ainsi, la boucle while ne sarrtera jamais delle-mme. Le contrle de cette boucle sobtient avec linstruction break sans laquelle ce type de boucle serait inutile. Vous pouvez aussi crer des boucles innies for ou do while:
for (;;) { /* instructions...*/ } do { /* instructions...*/ } while (1);

Ces trois boucles suivent le mme principe. Nous avons choisi, pour nos exemples, dutiliser une boucle while. Lintrt dune boucle innie est que lon peut faire de nombreux tests de conditions avant de dcider de larrt de cette boucle. En effet, il aurait t difcile dinclure tous ces tests entre

http://fribok.blogspot.com/

les parenthses de linstruction while. Il est plus facile de les effectuer sparment dans le corps de la boucle, puis de sortir avec une instruction break. Une boucle innie peut permettre de crer un menu systme pour orienter les oprations ralises par votre programme. Le Listing 13.4 vous en prsente un exemple. Listing 13.4 : Ralisation dun menu systme avec une boucle innie
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: /* Ralisation dun menu systme avec une boucle infinie. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> int menu(void); int main() { int choix; while (1) { /* Lecture du choix de lutilisateur. */ choix = menu(); /* Le branchement est ralis en fonction du choix. */ if (choix == 1) { puts("\nExcution de la tche correspondant au sleep(5); } else if (choix == 2) { puts("\nExcution de la tche correspondant au sleep(5); } else if (choix == 3) { puts("\nExcution de la tche correspondant au sleep(5); } else if (choix == 4) { puts("\nExcution de la tche correspondant au sleep(5); } else if (choix == 5)/* Sortie du programme. */ { puts("\nSortie du programme...\n"); sleep(5); break;

choix 1.");

choix 2.");

choix 3.");

choix 4.");

http://fribok.blogspot.com/

Listing 13.4 : Ralisation dun menu systme avec une boucle innie (suite)
46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: } else { puts("\nChoix incorrect, essayez de nouveau."); sleep(5); } } exit(EXIT_FAILURE); } /* Affichage du menu et lecture du choix de lutilisateur. */ int menu(void) { int reponse; puts("\nEntrez puts("Entrez 2 puts("Entrez 3 puts("Entrez 4 puts("Entrez 5 1 pour la tche A."); pour la tche B."); pour la tche C."); pour la tche D."); pour sortir du programme.");

scanf("%d", &reponse); return reponse; }

Entrez 1 pour la tche A. Entrez 2 pour la tche B. Entrez 3 pour la tche C. Entrez 4 pour la tche D. Entrez 5 pour sortir du programme. 1 Excution de la tche correspondant au choix 1 Entrez 1 pour la tche A. Entrez 2 pour la tche B. Entrez 3 pour la tche C. Entrez 4 pour la tche D. Entrez 5 pour sortir du programme. 6 Choix incorrect, essayez de nouveau. Entrez Entrez Entrez Entrez Entrez 5 Sortie 1 2 3 4 5 pour pour pour pour pour la tche A. la tche B. la tche C. la tche D. sortir du programme.

du programme ...

http://fribok.blogspot.com/

Analyse Ce programme contient une fonction menu() qui est appele la ligne 17 et dnie des lignes 58 71. Comme son nom lindique, cette fonction propose un menu lutilisateur, et renvoie le choix de celui-ci au programme appelant. La fonction main() contient plusieurs instructions if imbriques qui contrlent lexcution du programme en testant la valeur reue. Ce programme ne fait rien dautre quafcher des messages sur lcran, mais il aurait pu appeler une fonction pour chaque option prsente dans le menu.

Linstruction switch
Linstruction switch est linstruction de contrle la plus souple du langage C. Elle permet votre programme dexcuter diffrentes instructions en fonction dune expression qui pourra avoir plus de deux valeurs. Les instructions de contrle prcdentes, comme if, ne pouvaient valuer que deux valeurs dune expression : vrai ou faux. Cela obligerait, dans le cas dun test de plus de deux valeurs, utiliser des instructions imbriques comme dans notre exemple du Listing 13.4. Linstruction switch rsout ce problme de faon plus simple. La syntaxe de switch est la suivante :
switch (expression) { case modele_1: instruction(s); case modele_2: instruction(s); ... case modele_n: instruction(s); default: instruction(s); }

expression reprsente une expression qui peut tre value avec une valeur entire de type long, int ou char. Linstruction switch value cette expression, compare la valeur obtenue avec les modles fournis dans chaque instruction case, puis :

Si lexpression correspond un des modles noncs, linstruction qui suit linstruction case correspondante est excute. Si lexpression ne correspond aucun modle, cest linstruction situe aprs linstruction default qui est excute. Si lexpression ne correspond aucun modle, et que linstruction switch ne contient pas linstruction default, lexcution se poursuit avec linstruction qui suit laccolade de n de switch.

http://fribok.blogspot.com/

Le Listing 13.5 prsente un programme simple, qui afche un message en fonction du choix de lutilisateur. Listing 13.5 : Utilisation de linstruction switch
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: /* Utilisation de linstruction switch. */ #include <stdio.h> #include <stdlib.h> int main() { int reponse; puts("Entrez un nombre entre 1 et 5, ou 0 pour sortir: "); scanf("%d", &reponse); switch (reponse) { case 1: puts("Vous avez tap 1."); case 2: puts("Vous avez tap 2."); case 3: puts("Vous avez tap 3."); case 4: puts("Vous avez tap 4."); case 5: puts("Vous avez tap 5."); default: puts("choix incorrect, essayez de nouveau."); } exit(EXIT_SUCCESS); }

Entrez un nombre entre 1 et 5, ou 0 pour sortir: 2 Vous avez tap 2. Vous avez tap 3. Vous avez tap 4. Vous avez tap 5. Choix incorrect, essayez de nouveau.

Analyse Ce rsultat nest pas satisfaisant. Linstruction switch a trouv le modle, mais elle a excut toutes les instructions suivantes (pas seulement celle qui est associe au modle). En fait, switch ralise simplement un goto vers le modle correspondant lexpression. Pour nexcuter que les instructions associes ce modle, vous devez inclure une instruction break. Dans le Listing 13.6, le programme prcdent est revu et corrig en ce sens.

http://fribok.blogspot.com/

Listing 13.6 : Association des instructions switch et break


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: /* Exemple dutilisation correcte de linstruction switch. */ #include <stdio.h> #include <stdlib.h> int main() { int reponse; puts("\nEntrez un nombre entre 1 et 5, ou 0 pour sortir: "); scanf("%d", &reponse); switch (reponse) { case 1: { puts("Vous avez choisi break; } case 2: { puts("Vous avez choisi break; } case 3: { puts("Vous avez choisi break; } case 4: { puts("Vous avez choisi break; } case 5: { puts("Vous avez choisi break; } default: puts("Choix incorrect, } /* fin du switch */ exit(EXIT_SUCCESS); }

1.\n");

2.\n");

3.\n");

4.\n");

5.\n");

essayez de nouveau.\n");

list13_6 Entrez un nombre entre 1 et 5, ou 0 pour sortir: 1 Vous avez choisi 1. list13_6 Entrez un nombre entre 1 et 5: 6 Choix incorrect, essayez de nouveau.

http://fribok.blogspot.com/

Analyse Compilez et excutez cette version du programme ; le rsultat obtenu est correct. Limplmentation dun menu comme celui du Listing 13.6 est une des utilisations les plus courantes de switch. Le code ainsi obtenu est bien meilleur que celui des instructions if imbriques du Listing 13.4. Le programme du Listing 13.7 remplace les instructions if du Listing 13.4 par des instructions switch. Listing 13.7 : Ralisation dun menu systme avec linstruction switch
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: /* Utilisation dune boucle infinie avec linstruction switch */ /* pour implmenter un menu systme. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> int menu(void); int main() { int choix; while (1) { /* Branchement effectu en fonction du choix de lutilisateur. */ switch(choix=menu()) { case 1: { puts("\nExcution sleep(5); break; } case 2: { puts("\nExcution sleep(5); break; } case 3: { puts("\nExcution sleep(5); break; } case 4: { puts("\nExcution

du choix 1.");

du choix 2.");

du choix 3.");

du choix 4.");

http://fribok.blogspot.com/

41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74:

sleep(5); break; } case 5:/* Sortie du programme. */ { puts("\nSortie du programme...\n"); sleep(5); exit(0); } default: { puts("\nChoix incorrect, essayez de nouveau."); sleep(5); } } /* Fin du switch */ } /* Fin du while */ exit(EXIT_SUCCESS); } /* Affichage du menu et lecture du choix de lutilisateur. */ int menu(void) { int reponse; puts("\nEntrez puts("Entrez 2 puts("Entrez 3 puts("Entrez 4 puts("Entrez 5 1 pour excuter la tche A."); pour excuter la tche B."); pour excuter la tche C"); pour excuter la tche D."); pour sortir du programme.");

scanf("%d", &reponse); return reponse; }

Entrez 1 pour excuter la tche A. Entrez 2 pour excuter la tche B. Entrez 3 pour excuter la tche C. Entrez 4 pour excuter la tche D. Entrez 5 pour sortir du programme. 1 Excution du choix 1. Entrez Entrez Entrez Entrez Entrez 6 1 2 3 4 5 pour pour pour pour pour excuter la tche A. excuter la tche B. excuter la tche C. excuter la tche D. sortir du programme.

Choix incorrect, essayez de nouveau. Entrez 1 pour excuter la tche A. Entrez 2 pour excuter la tche B.

http://fribok.blogspot.com/

Entrez 3 pour excuter la tche C. Entrez 4 pour excuter la tche D. Entrez 5 pour sortir du programme. 5 Sortie du programme...

Analyse Cette version du programme utilise une nouvelle fonction de bibliothque : exit() (ligne 48). Cette fonction a t associe avec case5, car linstruction break ne peut tre utilise comme dans le Listing 13.4. En effet, break ne pourrait provoquer que la sortie de linstruction switch, pas celle de la boucle innie while. La fonction exit() arrte lexcution du programme. Dans certains cas, lexcution "groupe" dun sous-ensemble de linstruction switch est ncessaire. Pour, par exemple, que le mme bloc de code corresponde plusieurs valeurs diffrentes, il faut supprimer les instructions break correspondantes. Le programme du Listing 13.8 vous en donne un exemple. Listing 13.8 : Utilisation de linstruction switch
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: /* Autre exemple dutilisation de switch. */ #include <stdio.h> #include <stdlib.h> int main() { int reponse; while (1) { puts("\nEntrez une valeur entre 1 et 10, ou 0 pour sortir: scanf("%d", &reponse); switch (reponse) { case 0: exit(EXIT_SUCCESS)); case 1: case 2: case 3: case 4: case 5: { puts("Vous avez tap un chiffre entre 1 et 5.\n"); break; } case 6:

");

http://fribok.blogspot.com/

29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:

case 7: case 8: case 9: case 10: { puts("Vous avez tap un chiffre entre 6 et 10.\n"); break; } default: puts("On a dit entre 1 et 10, sil vous plait!\n"); } /* Fin du switch */ } /* Fin du while */ exit(EXIT_SUCCESS); }

Entrez une valeur entre 1 et 10, ou 0 pour sortir: 11 On a dit entre 1 et 10, sil vous plait! Entrez une valeur entre 1 et 10, ou 0 pour sortir: 1 Vous avez tap un chiffre entre 1 et 5. Entrez une valeur entre 1 et 10, ou 0 pour sortir: 6 Vous avez tap un chiffre entre 6 et 10. Entrez une valeur entre 1 et 10, ou 0 pour sortir: 0

Analyse Ce programme lit une valeur entre au clavier pour savoir si elle se situe entre 1 et 5, entre 6 et 10, ou en dehors de lintervalle 1-10. Si cette valeur est 0, la ligne 18 appelle la fonction exit() pour terminer le programme.

Syntaxe de linstruction switch


switch (expression) { case modele_1: instruction(s); case modele_2: instruction(s); ... case modele_n: instruction(s); default: instruction(s); }

Linstruction switch() permet de raliser plusieurs branchements partir dune seule expression. Elle est plus simple et plus efcace que lemploi de plusieurs niveaux de if. Linstruction switch value lexpression pour se positionner sur linstruction case dont le modle correspond au rsultat. Dans le cas o lexpression ne correspond aucun

http://fribok.blogspot.com/

modle, linstruction default est excute. Si cette instruction nexiste pas, lexcution se poursuit aprs la n de linstruction switch. Lexcution se fait ligne par ligne, jusqu ce quune instruction break soit rencontre. Le contrle est alors transfr la n de linstruction switch. Exemple 1
switch (lettre) { case A: case a: printf("vous avez tap A"); break; case B: case b: printf("vous avez tap B"); break; ... ... default: printf("je nai pas de rponse pour%c", lettre); }

Exemple 2
switch (nombre) { case 0:puts case 1:puts case 2:puts ... case 99:puts break; default:puts }

("Votre nombre est 0 ou moins."); ("Votre nombre est 1 ou moins."); ("Votre nombre est 2 ou moins."); ("Votre nombre est 99 ou moins."); ("Votre nombre est plus grand que 99.");

Les premires instructions case de cet exemple ne contiennent pas de break. Lexcution va donc afcher tous les messages de case, partir du nombre saisi au clavier jusquau nombre 99 qui prcde linstruction break.
eils Cons

ne pas faire Oublier dinclure les instructions break dont votre instruction switch a besoin. faire Inclure la ligne default dans votre instruction switch mme si vous pensez avoir prvu tous les cas de gure avec les diffrents case.

http://fribok.blogspot.com/

Utiliser une instruction switch plutt quune instruction if si plus de deux conditions sappliquent sur une mme variable. Aligner vos instructions case pour en faciliter la lecture.

Sortir du programme
Un programme C se termine naturellement quand lexcution atteint laccolade de n de la fonction main(). Il est possible, toutefois, darrter lexcution tout moment avec la fonction exit(), et de dnir une ou plusieurs fonctions qui devront sexcuter automatiquement la n du programme.

La fonction exit()
La fonction exit() interrompt lexcution du programme et redonne le contrle au systme dexploitation. Cette fonction possde un argument unique de type int, qui lui permet de transmettre au systme dexploitation une valeur indiquant le succs ou lchec de lexcution du programme. Cette fonction a la syntaxe suivante :
exit(status);

Si la valeur de status est 0, cela indique une n normale du programme. Une valeur de 1 indique, au contraire, quune erreur sest produite en cours dexcution. En gnral, on ignore cette valeur. Consultez la documentation de votre systme dexploitation si vous voulez contrler la valeur de retour dun de vos programmes. Le chier en-tte stdlib.h doit tre inclus pour que le programme puisse utiliser la fonction exit(). Ce chier dnit les deux constantes symboliques qui sont les arguments de cette fonction :
#define EXIT_SUCCESS #define EXIT_FAILURE 0 1

Ces deux constantes permettent de sortir du programme. Avec une valeur de retour gale 0, appelez exit(EXIT SUCCESS). Avec une valeur de retour gale 1, appelez exit(EXIT FAILURE).
eils Cons

faire Utiliser la commande exit() pour sortir du programme si une erreur se produit. Transmettre des valeurs signicatives la fonction exit().

http://fribok.blogspot.com/

Introduction de commandes systme dans un programme


La bibliothque standard de C contient une fonction, system(), qui permet dintroduire des commandes systme dans vos programmes. Vous pourrez, par exemple, consulter la liste des rpertoires dun disque, ou formater un disque sans sortir du programme. Cette fonction est disponible avec le chier en-tte stdlib.h. La syntaxe respecter est la suivante :
system(commande);

Largument commande peut tre une constante chane de caractres, ou un pointeur vers une chane. Voici, par exemple, comment vous pourriez obtenir la liste dun rpertoire de Windows :
system("dir");

ou
char *commande = "dir"; system(commande);

Sur Linux et les systmes Unix, remplacez "dir" par "ls". la n de lexcution de la commande systme, le contrle est rendu linstruction du programme qui suit lappel de la fonction system(). Si la commande que vous transmettez est incorrecte, vous recevez un message bad command ou file name error ou un message de ce type avant de revenir dans le programme. Le Listing 13.9 vous donne un exemple dutilisation de system(). Listing 13.9 : Utilisation de la fonction system() pour excuter des commandes systme
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: /* Illustration de la fonction system(). */ #include <stdio.h> #include <stdlib.h> int main() { /* Dclaration dune mmoire tampon pour y ranger les donnes */ /* entres. */ char input[40]; while (1) { /* lecture de la commande utilisateur. */ puts("\nEntrez une commande systme, ou une ligneblanche\ pour sortir");

http://fribok.blogspot.com/

16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:

lire_clavier(input, sizeof(input)); /* Sortie en cas de ligneblanche. */ if (input[0] == \0) exit(EXIT_SUCCESS); /* Excution de la commande. */

system(input); } exit(EXIT_SUCCESS); }

Entrez une commande systme, ou une ligneblanche pour sortir dir *.bak Volume in drive E is BRAD_VOL_B Directory of E:\BOOK\LISTINGS LIST1414 BAK141605-22-975:18p 1 file(s)1416 bytes 240068096 bytes free Entrez une commande DOS, ou une ligneblanche pour sortir

ce Astu

dir *.bak est une commande DOS/Windows qui demande au systme dafcher tous les chiers du rpertoire courant ayant lextension bak. Dans le cas dune machine UNIX, vous devrez taper ls *.bak pour obtenir le mme rsultat.

Analyse Ce programme lit les commandes systme saisies par lutilisateur en utilisant une boucle while (lignes 11 26). Si lutilisateur nentre pas de commande, la fonction exit() est appele en ligne 21. Sinon, la ligne 25 appelle la fonction system() en lui transmettant la commande saisie par lutilisateur. Bien sr, ce programme ne donnera pas les mmes rsultats si vous le faites tourner sur votre systme. Vous pouvez transmettre system() dautres commandes que les simples dir ou format. Vous pouvez lui indiquer le nom de tout chier excutable (binaire, script...). Par exemple, si largument transmis est list13_8, vous allez excuter le programme list13_8 avant de rendre le contrle linstruction qui suit lappel de system(). Les seules restrictions concernant system() sont lies la mmoire. Quand la fonction system() sexcute, le programme qui la appele reste charg dans la mmoire RAM de votre ordinateur. Des copies de la commande systme et du programme dont le nom a t transmis sont aussi charges en mmoire. Si la mmoire est insufsante, vous recevrez un message derreur.

http://fribok.blogspot.com/

Rsum
Le sujet trait dans ce chapitre est le contrle du programme. Vous savez pourquoi il ne faut pas utiliser linstruction goto (sauf quelques exceptions). Vous avez appris que les instructions break et continue permettent de contrler lexcution des boucles, et quelles vous seront trs utiles avec les boucles innies. Vous savez comment sortir du programme avec la fonction exit(). Enn, vous avez vu de quelle faon system() permet dexcuter des commandes systme depuis votre programme.

Q&R
Q Faut-il utiliser une instruction switch plutt quune boucle imbrique ? R Si la comparaison se fait sur une variable qui peut avoir plus de deux valeurs, linstruction switch sera presque toujours la meilleure solution. Le code sera aussi plus facile lire. Si vous testez une condition du type vrai/faux, utilisez if. Q Pourquoi faut-il viter linstruction goto? R Linstruction goto est attrayante, mais elle peut vous causer plus de problmes quelle nen rsout. Cest une instruction non structure qui vous branche un autre emplacement du programme. Beaucoup de dbogueurs (logiciels qui permettent de chercher des erreurs dans un programme) sont incapables dinterroger une instruction goto correctement. Cette instruction peut transformer votre code en code "spaghetti", cest-dire en code dans lequel on se dplace de faon anarchique. Q La fonction system() est-elle une bonne solution pour excuter des commandes systme ? R La fonction system() est une solution simple pour des oprations telles que la ralisation dune liste de chiers dans un rpertoire. Il faut toutefois tre conscient du fait que les commandes systme sont spciques chaque systme dexploitation. Si votre programme utilise system(), il est probable quil ne sera plus portable. Ce problme de portabilit nexiste pas dans le cas o system() excute un autre programme. Il existe par ailleurs quelques fonctions comme execv() ou execl() combiner avec fork() pour obtenir des rsultats plus complexes. Cela sort du cadre de ce livre.

Atelier
Cet atelier contient un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

http://fribok.blogspot.com/

Quiz
1. Quand faut-il utiliser une instruction goto dans un programme ? 2. Quelle est la diffrence entre une instruction break et une instruction continue? 3. Quest-ce quune boucle innie, et comment peut-on en crer une ? 4. Quels sont les deux vnements qui provoquent la n de lexcution dun programme ? 5. Quels sont les types de variables quune instruction switch peut valuer ? 6. quoi sert linstruction default? 7. quoi sert la fonction exit()? 8. quoi sert la fonction system()?

Exercices
1. crivez linstruction qui provoque le dmarrage immdiat de litration suivante dune boucle. 2. crivez les instructions qui arrtent un processus de bouclage pour donner le contrle linstruction qui suit la n de la boucle. 3. crivez la ligne de code qui afchera la liste des chiers du rpertoire courant . 4. CHERCHEZ LERREUR :
switch(reponse) { case Y: printf("Vous avez rpondu oui"); break; case N: printf("Vous avez rpondu non"); }

5. CHERCHEZ LERREUR :
switch (reponse) { default: printf("Vous navez choisi ni 1 ni 2."); case 1: printf("Vous avez rpondu 1"); break; case 2: printf("vous avez rpondu 2"); break; }

6. Recodez lexercice 5 en utilisant des instructions if.

http://fribok.blogspot.com/

7. crivez une boucle innie do while. Les deux exercices qui suivent ayant une multitude de solutions, les rponses ne sont pas fournies en Annexe F. 8. TRAVAIL PERSONNEL : crivez un programme qui fonctionne comme une calculatrice. Il devra permettre de faire des additions, des soustractions, des multiplications et des divisions. 9. TRAVAIL PERSONNEL : crivez un programme qui possde un menu avec cinq options diffrentes. La cinquime permettra de sortir du programme. Les quatre autres permettront dexcuter une commande systme laide de la fonction system().

http://fribok.blogspot.com/

14
Travailler avec lcran et le clavier
Les programmes effectuent presque tous des entres/sorties. Vous avez dj appris raliser les entres/sorties de base. Aujourdhui, vous allez tudier :

Lutilisation des ots dans les entres/sorties Les diffrentes faons de lire des donnes en provenance du clavier Les mthodes pour afcher du texte et des donnes numriques lcran La redirection des entres et des sorties dun programme

http://fribok.blogspot.com/

Les ots du C
Avant dtudier dans le dtail les entres/sorties, vous devez savoir ce que sont les ots. Toutes les entres/sorties du langage C se font avec les ots, quelle que soit leur origine ou destination. Vous constaterez que cette mthode standard de manipulation des entres/sorties prsente des avantages pour le programmeur. Il est bien sr essentiel, de bien comprendre ce que reprsentent les ots et leur fonctionnement.

Dnition des entres/sorties


Vous savez maintenant quun programme en cours dexcution range ses donnes dans la mmoire RAM. Ces donnes reprsentent les variables, les structures et les tableaux qui sont dclars dans le programme. Voici lorigine de ces donnes et ce que le programme peut en faire :

Les donnes sont issues dun emplacement externe au programme. Les donnes qui sont transfres en mmoire RAM pour que le programme puisse y accder, sont appeles les entres. Les entres proviennent le plus souvent du clavier ou de chiers sur disque. Les donnes peuvent aussi tre envoyes quelque part en dehors du programme : on les appelle alors les sorties. Les destinations les plus frquentes sont lcran, la sortie derreur et les chiers disque.

Les sources dentres et les destinations de sorties sont appeles units. Le clavier et lcran, par exemple, sont des units. Certaines units (le clavier) sont exclusivement rserves aux entres, dautres (lcran) servent aux sorties. Dautres encore (les chiers disque) permettent de faire des entres et des sorties. Quelle que soit lunit, le langage C effectue ses oprations dentres/sorties par lintermdiaire des ots.

Dnition dun ot
Un ot est une squence de caractres ou, plus exactement, une squence doctets de donnes. Une squence doctets qui arrive dans le programme est un ot dentres. Une squence doctets qui sort du programme est un ot de sorties. Le principal avantage des ots est que la programmation des entres/sorties est indpendante des units. Les programmeurs nont pas crer de fonctions particulires dentres/sorties pour chaque unit. Le programme "voit" ses entres/sorties comme un ot continu doctets, quelle que soit la source ou la destination de ces donnes. Chaque ot est connect un chier. Le terme de chier, ici, ne reprsente pas un chier disque. Il sagit plutt dune tape intermdiaire entre le ot avec lequel votre programme

http://fribok.blogspot.com/

travaille, et lunit physique utilise pour lentre ou la sortie. Ces chiers ne sont daucune utilit au programmeur C dbutant puisque le dtail des interactions entre les ots, les chiers et les units est pris en charge par les fonctions de la bibliothque du C et le systme dexploitation.
Figure 14.1 Les entres/sorties constituent le lien entre votre programme et de nombreuses units externes ou priphriques.
cran

Clavier

Rseau/Internet

Votre programme

Fichiers

Flots de texte versus ots binaires


Il existe deux modes pour les ots de C : le mode texte ou le mode binaire. Un ot texte est constitu exclusivement de caractres, comme par exemple un message que lon envoie sur lcran. Le ot texte est divis en lignes pouvant contenir 255 caractres chacune, qui se terminent par le caractre de retour la ligne. Certains caractres de ce ot ont une signication particulire. Ce chapitre est consacr aux ots texte. Un ot binaire peut contenir toute sorte de donnes, y compris les donnes texte. Les octets dun ot binaire ne sont pas interprts. Ils sont lus et crits tels quels. Les ots binaires sont utiliss avec les chiers disque tudis au Chapitre 16. Certains systmes dexploitation dont Linux ne font pas la diffrence entre ot texte et ot binaire : tout est considr comme ot binaire.

Les ots prdnis


La norme ANSI contient trois ots prdnis appels chiers entres/sorties standard. Ces ots sont ouverts automatiquement au dbut de lexcution dun programme C, et ferms la n du programme. Le Tableau 14.1 contient la liste des ots standard avec les

http://fribok.blogspot.com/

units qui leur sont normalement connectes. Ces ots standard appartiennent au mode texte.
Tableau 14.1 : Les cinq ots standard de C

Nom stdin stdout

Flot
Entre standard Sortie standard

Unit
Clavier cran

Chaque fois que vous avez utilis les fonctions printf() ou puts() pour afcher un texte lcran, vous avez utilis le ot stdout. De la mme faon, lorsque vous lisez les donnes entres au clavier avec scanf(), vous utilisez le ot stdin.

Les fonctions dentres/sorties


La bibliothque standard du C possde toute une varit de fonctions destines aux entres/sorties. Ces fonctions sont divises en deux catgories : la premire utilise toujours des ots standards, la seconde demande au programmeur de spcier le ot. Le Tableau 14.2 donne une liste partielle de ces fonctions.
Tableau 14.2 : Les fonctions entres/sorties de la bibliothque standard

Utilise un ot standard printf() vprintf() puts() putchar() scanf() gets() ( proscrire) getchar() perror()

Exige un nom de ot fprintf() vfprintf() fputs() putc(), fputc() fscanf() fgets() getc(), fgetc()

Action
Sortie formate Sortie formate avec une liste darguments Sortie chane Sortie caractre Entre formate Entre chane Entre caractre Sortie chane pour stderr

Lutilisation de toutes ces fonctions requiert le chier en-tte stdlib.h. Celui-ci devra aussi tre inclus pour la fonction perror(), et le chier stdargs.h est ncessaire pour les fonctions vprintf() et vfprintf(). Sur les systmes UNIX, vprintf() et vfprintf()

http://fribok.blogspot.com/

pourront ventuellement ncessiter varargs.h. La documentation relative la bibliothque de votre systme vous indiquera si des chiers en-tte supplmentaires sont requis.

Exemple
Le Listing 14.1 propose un programme court qui dmontre lquivalence des ots. Listing 14.1 : quivalence des ots
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: /* Dmonstration de lquivalence des flots dentres et de sorties. */ #include <stdio.h> #include <stdlib.h> int main() { char buffer[256]; /* Lecture dune ligne, puis affichage immdiat de cette ligne.*/ lire_clavier(buffer, sizeof(buffer)); puts(buffer); exit(EXIT_SUCCESS); }

La fonction lire clavier() de la ligne 9 permet de lire une ligne de texte partir du clavier. Cette fonction place la chane lue l o pointe buffer. Cette chane peut donc tre utilise comme argument pour la fonction puts() qui lafche lcran.
eils Cons

faire Proter des avantages offerts par les ots dentres/sorties standards de C. ne pas faire Transformer ou renommer les ots standards si ce nest pas ncessaire. Utiliser un ot dentre comme stdin pour une fonction comme fprintf() qui met une "sortie".

Les entres au clavier


Beaucoup de programmes C ont besoin de recevoir des informations en provenance du clavier (donc partir de stdin). Les fonctions dentres sont divises en trois catgories : les entres caractre, les entres ligne et les entres formates.

http://fribok.blogspot.com/

Entres caractre
Les fonctions dentres caractre lisent les donnes du ot, caractre par caractre. Quand elles sont appeles, chacune de ces fonctions renvoie le caractre suivant du ot, ou EOF si on a atteint la n du chier ou si une erreur se produit. EOF est une constante symbolique dnie dans stdio.h avec la valeur 1. Les fonctions dentres caractre prsentent quelques diffrences concernant lutilisation de la mmoire tampon et lcho gnr :

Certaines fonctions dentres caractre utilisent la mmoire tampon. Cela signie que le systme dexploitation stocke tous les caractres dans une mmoire temporaire, jusqu ce que vous appuyiez sur la touche Entre. Les caractres sont envoys dans le ot stdin. Dautres fonctions nutilisent pas cette mmoire tampon, et les caractres sont alors envoys un par un dans le ot stdin. Certaines fonctions dentres recopient automatiquement chaque caractre reu dans le ot stdout. Les autres se contentent denvoyer le caractre dans stdin. stdout reprsente lcran, cest donc sur lcran que cet "cho" est gnr.

La fonction getchar()
La fonction getchar() permet dobtenir le caractre suivant du ot stdin. Elle utilise la mmoire tampon et recopie les caractres lus sur lcran. Voici la syntaxe de sa dclaration :
int getchar(void);

Le Listing 14.2 illustre lutilisation de getchar(). Le rle de putchar(), qui sera expliqu plus loin dans ce chapitre, est dafcher un simple caractre lcran. Listing 14.2 : La fonction getchar()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: /* Illustration de la fonction getchar(). */ #include <stdio.h> #include <stdlib.h> main() { int ch; while ((ch = getchar())!= \n) putchar(ch); exit(EXIT_FAILURE); }

Voici ce que jai tap. Voici ce que jai tap.

http://fribok.blogspot.com/

Analyse La fonction getchar() est appele la ligne 9 et attend de recevoir un caractre de stdin. Cette fonction dentres utilisant la mmoire tampon, elle ne reoit aucun caractre tant que vous navez pas enfonc la touche Entre. Dans le mme temps, la valeur de chaque touche enfonce est afche lcran. Quand vous appuyez sur Entre, tous les caractres taps, y compris le caractre de retour la ligne, sont envoys vers le ot stdin par le systme dexploitation. La fonction getchar() renvoie les caractres un par un, et les attribue un par un la variable ch. Chacun de ces caractres est compar au caractre de retour la ligne "\n". Sil est diffrent de \n, le caractre est afch lcran avec putchar(). Quand la fonction getchar() renvoie le caractre de retour la ligne, la boucle while se termine. La fonction getchar() peut tre utilise pour lire des lignes de texte, comme le montre le Listing 14.3. Vous apprendrez plus loin dans ce chapitre que dautres fonctions conviennent mieux ce type dopration, en particulier la fonction lire clavier() que nous utilisons depuis le dbut de ce livre. Listing 14.3 : Lecture dune ligne de texte avec getchar()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: /* Utilisation de getchar() pour lire des chanes de caractres.*/ #include <stdio.h> #include <stdlib.h> #define MAX 80 int main() { char ch, buffer[MAX+1]; int x = 0; while ((ch = getchar())!= \n && x < MAX) buffer[x++] = ch; buffer[x] = \0; printf("%s\n", buffer); exit(EXIT_SUCCESS); }

Cela est une chane Cela est une chane

http://fribok.blogspot.com/

Analyse Ce programme utilise getchar() comme celui du Listing 14.2. La boucle contient toutefois une condition supplmentaire. La boucle while accepte de recevoir des caractres de la part de getchar() jusqu ce quelle trouve un caractre de retour la ligne, ou que le nombre de caractres lus soit de 80. Chaque caractre est stock dans le tableau buffer[]. Quand tous les caractres ont t lus, la ligne 15 ajoute le caractre nul la n du tableau pour que la fonction printf() de la ligne 17 puisse afcher la chane. La taille choisie pour le tableau buffer (ligne 9) est de MAX+1. Ce choix permettra de lire une chane de 80 caractres laquelle on ajoutera le caractre nul ( ne pas oublier).

La fonction getch()
La fonction getch() permet dobtenir le caractre suivant du ot stdin. Elle nutilise pas la mmoire tampon et nenvoie pas dcho vers lcran. Cette fonction ne fait partie ni du standard ANSI/ISO ni dun standard rpandu tel que POSIX ou BSD, elle pourrait donc ne pas tre disponible sur tous les systmes, en particulier Unix et Linux. Elle pourrait de plus imposer linclusion de divers chiers en-tte. La dclaration de cette fonction, qui se trouve gnralement dans le chier en-tte conio.h, a la forme suivante :
int getch(void);

getch() envoie chaque caractre lu au clavier vers stdin sans attendre que lutilisateur appuie sur la touche Entre. Elle ne recopie pas ces caractres dans stdout, vous ne les verrez donc pas apparatre lcran.
ntion Atte

Le listing qui suit utilise getch(), qui nappartient ni au standard ANSI/ISO ni un standard rpandu tel que POSIX ou BSD. Utilisez prudemment ce type de fonction, car elle pourrait ne pas tre reconnue par certains compilateurs. Si vous obtenez des erreurs en compilant ce listing, votre compilateur en fait peuttre partie.

Listing 14.4 : La fonction getch()


1: /* Utilisation de la fonction getch(). */ 2: /* code non ANSI */ 3: #include <stdio.h> 4: #include <stdlib.h> 5: #include <conio.h> 6: int main() 7: { 8: int ch; 9:

http://fribok.blogspot.com/

10: while ((ch = getch())!= \r) 11: putchar(ch); 12: exit(EXIT_SUCCESS); 13: } Test de la fonction getch()

Analyse Quand ce programme sexcute, getch() envoie immdiatement vers stdin, chaque caractre que vous avez tap. Cette fonction nenvoyant pas dcho vers la sortie standard, vous voyez apparatre vos caractres sur lcran grce la fonction putchar(). Pour mieux comprendre le fonctionnement de getch(), ajoutez un point-virgule la n de la ligne 10 et supprimez la ligne 11 (putchar()). En excutant de nouveau ce programme, vous constaterez que les caractres taps ne sont plus afchs. La fonction getch() les rcupre en effet sans les reproduire lcran. Vous savez que ces caractres ont bien t lus parce que le listing initial avait fait appel putchar() pour les afcher. Ce programme compare chaque caractre reu avec le caractre \r, qui est le code correspondant au caractre "retour chariot". Quand vous appuyez sur la touche Entre, le clavier envoie un caractre retour chariot (CR) vers stdin. Les fonctions dentres caractre qui utilisent la mmoire tampon convertissent automatiquement ce retour chariot en caractre de retour la ligne. Cest pourquoi les programmes testent plutt, dans ce cas, le caractre \n pour savoir si lutilisateur a appuy sur Entre. Le Listing 14.3 vous prsente un exemple dutilisation de getch() pour lire une ligne entire de texte. En excutant ce programme, vous pourrez constater labsence dcho lcran avec getch(). Listing 14.5 : Lecture dune ligne de texte avec la fonction getch()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: /* Utilisation de getch() pour lire des chanes de caractres. */ /* Code non ISO/ANSI */ #include <stdio.h> #include <stdlib.h> #include <conio.h> #define MAX 80 int main() { char ch, buffer[MAX+1]; int x = 0; while ((ch = getch())!= \r && x < MAX) buffer[x++] = ch;

http://fribok.blogspot.com/

Listing 14.5 : Lecture dune ligne de texte avec la fonction getch() (suite)
16: buffer[x] = \0; 17: 18: printf("%s", buffer); 19: exit(EXIT_SUCCESS); 20: } 21: Cela est une chane Cela est une chane

La fonction getche()
La seule diffrence entre getch() et getche() est que celle-ci envoie un cho des caractres vers lcran. Modiez le programme du Listing 14.4 en remplaant getch() par getche(). Vous pourrez constater que chaque caractre tap sera afch deux fois sur lcran : la premire fois est due lcho de getche(), et la seconde, la fonction putchar().
ntion Atte

getche() nest pas une fonction standard ISO/ANSI ni daucun standard rpandu comme POSIX ou BSD.

Les fonctions getc() et fgetc()


Ces deux fonctions dentres caractre nutilisent pas automatiquement stdin; le ot dentres doit tre spci par le programme. Elles sont utilises pour lire des caractres partir des chiers disque qui sont tudis au Chapitre 16.
eils Cons

faire Distinguer les entres simples des entres qui sont envoyes en cho sur lcran. Distinguer les entres qui utilisent la mmoire tampon de celles qui ne lutilisent pas. ne pas faire Utiliser des fonctions non ISO/ANSI pour obtenir un code portable.

Comment "rendre" un caractre avec ungetc()


Nous allons utiliser un exemple pour vous expliquer ce que signie "rendre" un caractre. Imaginons que votre programme soit en train de lire les caractres du ot dentres, et que

http://fribok.blogspot.com/

la seule mthode pour dtecter la n de cette lecture soit de lire un caractre de trop. Par exemple, si vous lisez des chiffres, vous saurez quil ny a plus de donnes lire quand vous rencontrerez le premier caractre qui ne sera pas un chiffre. Celui-ci est le premier caractre de lentre suivante, mais il ne se trouve plus dans le ot. Vous pouvez ly replacer, ou le "rendre", pour que la prochaine opration sur ce ot puisse lire ce caractre. Pour cela, vous devez utiliser la fonction de la bibliothque ungetc() dont la dclaration a la forme suivante :
int ungetc(int ch, FILE *fp);

Largument ch est le caractre renvoyer. Largument *fp identie le ot vers lequel le caractre doit tre envoy. La notation FILE *fp est utilise pour les ots associs des chiers disque (voir Chapitre 16). Si le ot est le ot standard vous crirez :
ungetc(ch, stdin);

Vous ne pouvez rendre quun seul caractre un ot entre deux lectures, et ce caractre ne peut tre le caractre EOF. Le programme du Listing 17.16 utilise cette fonction ungetc().

Entres ligne
Les fonctions dentres ligne lisent tous les caractres dun ot dentres jusquau premier caractre de retour la ligne. La bibliothque standard contient deux fonctions dentres ligne : gets() et fgets(). La fonction gets() Mise en garde : cette fonction est dangereuse. Nous la prsentons ici pour mieux vous montrer pourquoi elle est proscrire. La fonction gets() permet de lire une ligne complte dans stdin et de la stocker dans une chane de caractres. La dclaration de cette fonction a la syntaxe suivant :
char *gets(char *str);

Largument de cette fonction est un pointeur vers une variable de type char, et la valeur renvoye est un pointeur du mme type. Elle lit les caractres de stdin jusqu ce quelle rencontre le caractre de retour la ligne (\n) ou une n de chier. Le caractre de retour la ligne est remplac par le caractre nul, et la chane est stocke ladresse pointe par str. La valeur renvoye est un pointeur vers la chane de caractres lue (le mme que str). Si gets() rencontre une erreur ou lit une n de chier avant de lire un caractre, le pointeur renvoy sera un pointeur nul.

http://fribok.blogspot.com/

Avant dappeler la fonction gets(), il faut allouer assez de mmoire pour stocker la chane. La fonction ne peut pas savoir si ladresse pointe par ptr est un emplacement rserv ou non. Dans tous les cas, la chane sera stocke cet endroit. Si lespace na pas t rserv auparavant, les donnes qui sy trouvaient sont crases. Mais surtout, si lespace rserv tait insufsant, les donnes au-del de la zone rserve sont galement crases. Comme il est impossible de connatre la taille de lespace mmoire rserver, le programme nest donc jamais labri dun utilisateur malveillant (autrement dit, un pirate) qui entrerait plus de caractres que le programmeur en a prvu et qui pourrait de cette faon agir sur votre ordinateur de faon indsirable. Dans ces conditions, soyez-en prvenus : nutilisez jamais gets(), mais fgets(), prsente plus loin et qui, utilise comme ci-dessous, est quivalente gets(), sans le problme de scurit :
char buffer[80]; fgets(buffer, sizeof(buffer), stdin);

La fonction fgets() Comme la fonction gets(), fgets() permet de lire une ligne de texte dans un ot dentres. Elle est plus souple, car elle autorise le programmeur spcier le ot dentres utiliser et le nombre maximum de caractres lire. Cette fonction est souvent utilise pour lire du texte dans des chiers disque (voir Chapitre 16). Voici la dclaration de fgets():
char *fgets(char *str, int n, FILE *fp);

Le dernier paramtre FILE *fp reprsente le ot dentres. Contentez-vous aujourdhui de le remplacer par stdin. Le pointeur str indique o la chane est stocke, et largument n est le nombre maximum de caractres lire. fgets() va lire les caractres du ot dentres jusqu ce quelle rencontre un caractre de n de ligne ou de retour la ligne, ou quelle ait lu n 1 caractres. Le caractre de retour la ligne est inclus dans la chane avant de la stocker. Les valeurs renvoyes par fgets() sont les mmes que celles de la fonction gets(). Pour tout dire, si vous dnissez une ligne comme tant une suite de caractres termine par un retour la ligne, fgets() ne lit pas une simple ligne de texte. Elle ne lira quune partie dune ligne contenant plus de n 1 caractres. Avec stdin, lexcution de fgets() se poursuivra jusqu ce que vous tapiez sur la touche Entre, mais seuls n 1 caractres seront stocks dans la chane. Le Listing 14.6 prsente le fonctionnement de la fonction fgets().

http://fribok.blogspot.com/

Listing 14.6 : La fonction fgets()


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: /* Exemple dutilisation de la fonction fgets(). */ #include <stdio.h> #include <stdlib.h> #define MAXLONG 10 int main() { char buffer[MAXLONG]; puts("Entrez une lignede texte la fois, ou un blanc \ pour sortir."); while (1) { fgets(buffer, MAXLONG, stdin); if (buffer[0] == \n) break; } puts(buffer);

exit(EXIT_SUCCESS); }

Entrez une lignede texte la fois, ou un blanc pour sortir. Les roses sont rouges Les roses sont rou ges Les violettes sont bleues Les viole ttes sont bleues Programmer enC programme r enC Est bon pour vous! Est bon p our vous !

La fonction fgets() apparat en ligne 15. En excutant ce programme, entrez des lignes dune longueur infrieure, puis suprieure MAXLEN et observez le rsultat. Dans le cas dune longueur suprieure, le premier appel de fgets() lit les MAXLEN 1 premiers caractres, les autres tant stocks dans la mmoire tampon du clavier. Ils sont lus ensuite par un second appel de fgets() ou par toute autre fonction qui lit partir de stdin. Le programme se termine lorsquil reoit une ligne vide (lignes 17 et 18).

http://fribok.blogspot.com/

Les entres formates


Les fonctions dentres que nous avons tudies jusqu prsent prenaient simplement un ou plusieurs caractres dans un ot dentres pour les stocker quelque part en mmoire. Ces caractres ntaient ni formats, ni interprts, et vous ne pouviez pas lire des variables numriques. Pour lire partir du clavier la valeur 12.86, par exemple, et lattribuer une variable de type float, vous devrez utiliser les fonctions scanf() et fscanf(). Nous avons tudi ces fonctions au Chapitre 7. Ces deux fonctions sont analogues. scanf() utilise toujours stdin, alors que fscanf() utilise le ot dentres spci par lutilisateur. fscanf() est utilise pour les entres chier qui sont traites au Chapitre 16.

Les arguments de la fonction scanf()


La fonction scanf() prend un minimum de deux arguments. Le premier est la chane format qui utilise des caractres spciaux pour indiquer scanf() comment interprter les entres. Les arguments suivants reprsentent les adresses des variables dans lesquelles seront stockes les donnes dentres. Voici un exemple :
scanf("%d", &x);

Le premier argument "%d" est la chane format. Dans cet exemple, "%d" indique scanf() de chercher une valeur entire signe. Le second argument utilise loprateur dadresse (&) pour demander scanf() dattribuer la valeur de lentre la variable x. Examinons en dtail la chane format. Voici les trois lments que lon peut introduire dans une chane format :

Des blancs et des tabulations qui seront ignors. Des caractres (sauf %) qui seront associs tous les caractres lus (sauf les blancs). Une ou plusieurs conversions qui seront constitues du caractre % suivi dun caractre particulier. En gnral, la chane format contient une conversion par variable.

Les conversions reprsentent la seule partie obligatoire de la chane format. Chacune dentre elles commence par le caractre % suivi de composants obligatoires ou optionnels dans un certain ordre. La fonction scanf() applique les demandes de conversions de la chane format, dans lordre, aux champs du ot dentres. Un champ dentres est une squence de caractres qui se termine au premier blanc rencontr ou quand la largeur de champ spcie est atteinte. Les composants dun ordre de conversion sont les suivants :

Lindicateur de suppression dattribution (*) qui est optionnel et plac immdiatement aprs %. Ce caractre demande scanf() de raliser la conversion en cours, mais den ignorer le rsultat (ne pas en attribuer la valeur la variable).

http://fribok.blogspot.com/

La largeur de champ qui est aussi optionnelle. Ce composant est un nombre dcimal qui indique le nombre de caractres du champ dentres. En dautres termes, la largeur de champ indique scanf() le nombre de caractres quelle doit prendre en compte dans stdin pour la conversion en cours. Si la largeur de champ nest pas indique, scanf() lira tous les caractres jusquau premier blanc.
ntion Atte

Si vous lisez une chane de caractres (indicateur de type s), il est impratif (et malheureusement facultatif) que vous indiquiez une largeur de champ. Sinon, vous introduisez une faille de scurit dans votre code, la mme que celle dcrite plus haut relative gets().

Le composant suivant est toujours optionnel, il sagit de lattribut de prcision. Celuici est le simple caractre h, l ou L. Il permet de changer la signication du type de variable qui le suit (voir plus loin). Le seul composant obligatoire dune conversion (en dehors de %) est lindicateur du type. Cet indicateur est reprsent par un ou plusieurs caractres indiquant scanf() comment il doit interprter les donnes lues. Le Tableau 14.3 donne la liste de ces caractres avec leur explication. La colonne "Argument" donne le type de variable correspondant lindicateur de type de scanf(). Un indicateur de type d, par exemple, doit sappliquer une variable lue de type int * (un pointeur de variable de type int).

Tableau 14.3 : Liste des caractres utiliss pour les spcications de conversion de scanf()

Type d i o u x c

Argument int * int * int *


unsigned int *

Signication
Entier dcimal. Entier exprim en base 10, 8 (premier chiffre 0) ou 16 (commence par 0X ou 0x). Entier exprim en base 8 avec ou sans 0 devant. Entier dcimal non sign. Entier hexadcimal avec ou sans 0X ou 0x devant. Les caractres sont lus et stocks squentiellement ladresse mmoire indique par largument. Le caractre de n \0 nest pas ajout. Sans argument de largeur de champ, la lecture se fait sur un seul caractre. Si cet argument est donn, la lecture se fait sur le nombre de caractres indiqu en incluant les blancs. La chane de caractres (sans blancs) est lue et stocke ladresse indique par largument en lui ajoutant le caractre de n \0.

int * char *

char *

http://fribok.blogspot.com/

Tableau 14.3 : Liste des caractres utiliss pour les spcications de conversion de scanf() (suite)

Type e,f,g [...]

Argument float * char *

Signication
Nombre avec une virgule ottante. Ces nombres peuvent tre lus en notation dcimale ou scientique. Chane de caractres. Seuls, les caractres entre crochets sont lus. La lecture est interrompue ds larrive dun caractre ne faisant pas partie de la liste, ou ds que le nombre de caractres atteint la largeur de champ, ou encore si la touche Entre est enfonce. Pour que le caractre ] soit lu, il doit tre plac en premier : []...]. \0 est ajout en n de chane. Analogue [...]. Tous les caractres sont accepts lexception de ceux entre crochets. Ce caractre nest pas stock, il est seulement lu comme le caractre %.

[^...]

char * None

Avant de voir des exemples dutilisation de la fonction scanf(), vous devez comprendre le rle des attributs de prcision du Tableau 14.4.
Tableau 14.4 : Les attributs de prcision

Attribut de prcision h

Signication
Plac avant lindicateur de type d, i, o, u ou x, lattribut h indique que largument est un pointeur vers une variable de type short , plutt que de type int. Sur un PC, short et int sont identiques ; h ne sera donc jamais utilis. Quand on le place avant lindicateur de type d, i, o, u ou x, il indique que largument est un pointeur de type long. Plac avant e, f ou g, lattribut l indique que largument est un pointeur de type double. Plac avant lindicateur de type e, f ou g, cet attribut indique que largument est un pointeur de type long double.

Le traitement des caractres parasites


La fonction scanf() utilise la mmoire tampon. Elle ne reoit aucun caractre tant que lutilisateur na pas appuy sur la touche Entre. La ligne entire de caractres est alors envoye dans stdin pour tre traite par scanf(). Lexcution de scanf() se termine lorsquelle a trait le nombre de champs dentres correspondant aux conversions de sa chane format. Si des caractres subsistent dans stdin aprs la n de lexcution de scanf(), ils risquent de provoquer des erreurs. Examinons le fonctionnement de scanf() pour en comprendre la raison.

http://fribok.blogspot.com/

Quand scanf() est appele alors que lutilisateur vient dentrer une ligne de texte, trois situations peuvent se prsenter. Pour notre exemple, supposons que linstruction scanf("%d %d", &x, &y) ait t excute. Elle sattend recevoir deux entiers dcimaux :

Premier cas, la ligne entre par lutilisateur correspond en tout point la chane format. Il a pu, par exemple, saisir 1214 puis Entre. scanf() sexcute normalement et le ot stdin ne contiendra plus de caractres. Deuxime cas, la ligne entre par lutilisateur ne contient pas assez dlments pour satisfaire la chane format. Il a pu saisir, par exemple, 12 puis Entre. scanf() va alors attendre les donnes manquantes. Lexcution se poursuit aprs la rception de ces donnes et stdin ne contient plus de caractres. Troisime cas, la ligne entre par lutilisateur a plus dlments que nen demande la chane format. Lutilisateur a tap 121416 puis Entre, par exemple. scanf() va lire 12 et 14 avant de rendre le contrle au programme appelant. Les deux caractres supplmentaires 1 et 6 vont rester en attente dans stdin.

Voici pourquoi cette troisime situation peut tre lorigine de problmes. Ces deux caractres vont rester dans stdin aussi longtemps que le programme sexcutera. Ils seront donc prsents lors de la lecture suivante de stdin et ils seront les premiers caractres traits. Pour viter de telles erreurs, vous avez deux solutions. La premire est que les utilisateurs de vos programmes ne se trompent jamais. Elle sera plutt difcile mettre en uvre. Une meilleure solution consiste sassurer quaucun caractre parasite ne subsiste dans le ot avant de demander des donnes lutilisateur. Vous pouvez, pour cela, appeler fgets() qui lira tous les caractres restant dans stdin, y compris le caractre de n de ligne. Plutt que dappeler fgets() directement dans vos programmes, vous pouvez crer une fonction spcique appele clear kb() comme le montre le Listing 14.7. Listing 14.7 : Suppression des caractres parasites de stdin
1: /* Nettoyage de stdin. */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: void clear_kb(void); 6: 7: int main() 8: { 9: int age; 10: char nom[20]; 11: 12: /* On demande lge de lutilisateur. */

http://fribok.blogspot.com/

Listing 14.7 : Suppression des caractres parasites de stdin (suite)


13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: puts("Entrez votre ge: "); scanf("%d", &age); /* On retire de stdin les caractres parasites. */ clear_kb(); /* Lecture du nom de lutilisateur. */ puts("Entrez votre nom: "); scanf("%19s", nom); /* Affichage des donnes. */ printf("Vous avez%d ans.\n", age); printf("Vous vous appelez%s.\n", nom); exit(EXIT_SUCCESS); } void clear_kb(void) /* On efface de stdin les caractres restants. */ { char junk[80]; fgets(junk, sizeof(junk) stdin); }

Entrez votre ge: 29 et pas un an de plus! Entrez votre nom: Bradley Vous avez 29 ans. Vous vous appelez Bradley.

Analyse En excutant le programme du Listing 14.7, entrez des caractres supplmentaires aprs votre ge. Assurez-vous que le programme les ignore et quil interprte correctement votre nom. Modiez ensuite ce programme en supprimant lappel de la fonction clear kb() et relancez-le. Les caractres parasites taps aprs votre ge vont tre attribus votre nom.

Le traitement des caractres parasites avec fflush()


Il existe une autre mthode pour effacer les caractres superus. La fonction fflush() fait disparatre les informations prsentes dans un ot, y compris le ot dentre standard. Elle est gnralement utilise avec les chiers sur disque (traits au Chapitre 16). Elle peut

http://fribok.blogspot.com/

cependant simplier le Listing 14.7. Le Listing 14.8 lutilise la place de la fonction clear kb(), qui avait t cre dans le Listing 14.7. Listing 14.8 : Nettoyage de stdin avec fush ()
1: /* Nettoyage de stdin avec fflush(). */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: int main() 6: { 7: int age; 8: char name[20]; 9: 10: /* On demande lge de lutilisateur. */ 11: puts("Entrez votre ge."); 12: scanf("%d", &age); 13: 14: /* On retire de stdin les caractres parasites. */ 15: fflush(stdin); 16: 17: /* Lecture du nom de lutilisateur. */ 18: puts("Entrez votre nom."); 19: scanf("%19s", name); 20: 21: /* Affichage des donnes. */ 22: printf("Vous avez%d ans.\n", age); 23: printf("Vous vous appelez%s.\n", name); 24: 25: exit(EXIT_SUCCESS); 26: }

Lexcution de ce programme donne le rsultat :


Entrez votre ge. 29 et pas un an de plus! Entrez votre nom. Bradley Vous avez 29 ans. Vous vous appelez Bradley.

La fonction fflush() apparat en ligne 15, et son prototype est le suivant :


int fflush( FILE *flot);

flot reprsente le ot "nettoyer". Dans le Listing 14.8, cest le ot dentre standard stdin qui a t transmis comme flot.

http://fribok.blogspot.com/

Exemples avec scanf()


La meilleure faon de se familiariser avec les oprations de la fonction scanf(), cest de les tester. Le programme du Listing 14.10 vous prsente quelques utilisations de cette fonction parmi les moins courantes. Compilez ce programme puis excutez-le. Faites ensuite quelques tests en modiant les chanes format de scanf(). Listing 14.9 : Exemples dutilisation de scanf() pour les entres au clavier
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: /* Exemple dutilisations de scanf(). */ #include <stdio.h> #include <stdlib.h>

int main() { int i1, i2; long l1; double d1; char buf1[80], buf2[80]; /* Utilisation de l pour entrer des entiers de types long et double. */ puts("Entrez un entier et un nombre avec une virgule: "); scanf("%ld%lf", &l1, &d1); printf("\nVous avez tap%ld et%lf.\n",l1, d1); puts("La chane format de scanf() a utilis lattribut l"); puts("pour stocker vos donnes dans une variable de type"); puts("long et une autre de type double.\n"); fflush(stdin); /* Utilisation de la largeur du champ pour couper les donnes entres. */ puts("Entrez un entier de 5 chiffres (par exemple, 54321):"); scanf("%2d%3d", &i1, &i2); printf("\nVous avez tap%d et%d.\n", i1, i2); puts("Notez comment lindicateur de largeur de champ "); puts("de la chane format de scanf() a spar votre valeur \ en deux.\n"); fflush(stdin); /* Utilisation dun espace exclu pour stocker une ligne*/ /* entre dans deux chanes. */ puts("Entrez vos nom et prnom spars par un blanc: "); scanf("%[^ ]%80s", buf1, buf2); printf("\nVotre nom est%s\n", buf1); printf("Votre prnom est%s\n", buf2);

http://fribok.blogspot.com/

44: 45: 46: 47: 48:

puts("Notez comment le caractre [^ ] de la chane format de"); puts("scanf(), en excluant le caractre blanc, a spar \ les donnes entres."); exit(EXIT_SUCCESS); }

Entrez un entier et un nombre avec une virgule: 12345.6789 Vous avez tap 123 et 45.678900. La chane format de scanf() a utilis lattribut l pour stocker vos donnes dans une variable de type long et une autre de type double. Entrez un entier de 5 chiffres (par exemple 54321): 54321 Vous avez tap 54 et 321. Notez comment lindicateur de largeur de champ de la chane format de scanf() a spar votre valeur en deux. Entrez vos nom et prnom spars par un blanc: Peter Aitken Votre nom est Peter, Votre prnom est Aitken Notez comment le caractre [^ ] de la chane format de scanf(), en excluant le caractre blanc, a spar les donnes entres.

Analyse Le source de ce programme commence avec la dnition de plusieurs variables (lignes 9 13) qui contiendront les donnes lues. Le programme demande ensuite lutilisateur dentrer divers types de donnes. Les lignes 17 22 lisent et afchent un entier long et un autre de type double. La ligne 24 appelle la fonction fflush() pour effacer les caractres parasites du ot dentres. Les lignes 28 et 29 demandent ensuite un entier de 5 chiffres. La chane format contenant des indications de largeur de champ, cet entier est coup en deux. La fonction fflush() est appele de nouveau la ligne 35 pour vider stdin. Le dernier exemple (lignes 40 47), utilise le caractre dexclusion. En effet, "%[^]%80s" la ligne 41 demande scanf() de lire une chane de caractres et darrter sa lecture au premier blanc rencontr. Cela a permis de sparer les deux mots entrs sur la mme ligne. La fonction scanf() peut tre utilise pour traiter la plupart de vos entres, en particulier celles qui contiennent des nombres (les chanes sont traites plus facilement avec fgets()). Toutefois, il est souvent prfrable dcrire ses propres fonctions dentres. Le Chapitre 18 vous prsentera quelques exemples de fonctions dentres utilisateur.

http://fribok.blogspot.com/

eils Cons

faire Utiliser les caractres tendus dans vos programmes an de conserver une bonne cohrence avec les autres programmes. Utiliser scanf() plutt que fscanf() si vous nutilisez que le ot stdin et que vous lisez des nombres. Rservez fgets() pour les chanes de caractres. ne pas faire Oublier de contrler la prsence de caractres parasites dans le ot dentres. Utiliser gets(). Utiliser scanf() pour des chanes de caractres sans prciser dindicateur de taille.

Les sorties cran


Les fonctions de sorties cran sont divises en trois catgories principales, sur le mme principe que les fonctions dentres : les sorties caractre, les sorties ligne et les sorties formates. Nous avons utilis quelques-unes de ces fonctions dans les chapitres prcdents.

Sorties caractre avec putchar(), putc() et fputc()


Les fonctions de sorties caractre de la bibliothque C envoient un simple caractre dans un ot. La fonction putchar() envoie ses caractres vers stdout (gnralement lcran). Les fonctions fputc() et putc() envoient leurs sorties dans le ot indiqu dans la liste des arguments.

Utilisation de putchar()
La dclaration de putchar() se trouve dans le chier en-tte stdio.h :
int putchar(int c);

La fonction envoie le caractre stock dans c vers stdout. Bien que largument indiqu dans cette dclaration soit de type int, vous transmettez la fonction une variable de type char. Vous pouvez aussi lui transmettre une variable de type int, du moment que sa valeur appartient lintervalle autoris (0 255). La fonction renvoie le caractre qui vient dtre crit ou EOF si elle a rencontr une erreur. Le programme du Listing 14.2 que nous avons tudi contient une fonction putchar(). Celui du Listing 14.11 afche les valeurs ASCII des caractres compris entre 14 et 127

http://fribok.blogspot.com/

Listing 14.10 : La fonction putchar()


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: /* La fonction putchar(). */ #include <stdio.h> #include <stdlib.h> int main() { int count; for (count = 14; count < 128;) putchar(count++); exit(EXIT_SUCCESS); }

Vous pouvez aussi afcher des chanes de caractres avec la fonction putchar() (voir Listing 14.11). Listing 14.11 : Afchage dune chane de caractres avec putchar()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: /* Utilisation de putchar() pour afficher des chanes. */ #include <stdio.h> #include <stdlib.h> #define MAXSTRING 80 char message[] = "Affich avec putchar()."; int main() { int count; for (count = 0; count < MAXSTRING; count++) { /* On cherche la fin de la chane. Quand on la trouve, on crit /* le caractre de retour la ligneet on sort de la boucle. */ if (message[count] == \0) { putchar(\n); break; } else */

/* Si ce nest pas la fin de la chane, on crit le prochain */ /* caractre. */ putchar(message[count]); } exit(EXIT_SUCCESS); }

Affich avec putchar().

http://fribok.blogspot.com/

Les fonctions putc() et fputc()


Ces deux fonctions sont analogues, elles envoient un caractre vers le ot indiqu. putc() est limplmentation macro de fputc() (les macros sont tudies au Chapitre 21). La dclaration de fputc() a la forme suivante :
int fputc(int c, FILE *fp);

Le ot de sorties est transmis la fonction par lintermdiaire de largument FILE *fp (voir Chapitre 16). Si le ot indiqu est stdout, fputc() se comportera exactement comme putchar(). Les deux instructions suivantes sont donc quivalentes :
putchar(x); fputc(x, stdout);

Utilisation de puts() et fputs() pour les sorties chane


Vos programmes auront plus souvent besoin dafcher des chanes que de simples caractres. la fonction de bibliothque puts() permet dafcher des chanes de caractres. La fonction fputs() envoie la chane dans le ot indiqu. La dclaration de puts() a la forme suivante :
int puts(char *cp);

*cp est un pointeur vers le premier caractre de la chane que vous voulez afcher. La fonction puts() afche la chane complte jusquau caractre qui prcde le caractre nul de n, et y ajoute le caractre de retour la ligne. puts() renvoie une valeur positive si son excution sest droule correctement, ou EOF si une erreur sest produite. La fonction puts() peut afcher tout type de chane de caractres comme le montre le Listing 14.12. Listing 14.12 : La fonction puts()
1: /* La fonction puts(). */ 2: #include <stdio.h> 3: #include <stdlib.h> 4: 5: /* Declare and initialize an array of pointers. */ 6: 7: char *messages[5] = { "Ceci", "est", "un", "message", "court." }; 8: 9: int main() 10: { 11: int x; 12: 13: for (x=0; x<5; x++)

http://fribok.blogspot.com/

14: puts(messages[x]); 15: 16: puts("et cela est la fin!"); 17: 18: exit(EXIT_SUCCESS); 19: } Ceci est un message court. et cela est la fin!

Analyse Ce programme dclare un tableau de pointeurs. Ce type de tableau sera tudi au Chapitre 15. Les lignes 13 et 14 afchent chaque chane stocke dans le tableau message.

Utilisation de printf() et fprintf() pour les sorties formates


Les fonctions de sorties prcdentes nafchent que des caractres ou des chanes. Pour afcher des nombres, il faut utiliser les fonctions de sorties formates de la bibliothque C : printf() et fprintf(). Ces fonctions sont aussi capables dafcher les caractres. Nous avons tudi la fonction printf() au Chapitre 7, et nous lavons utilise dans presque tous les exemples. Ce paragraphe vous fournira les ultimes dtails. Les deux fonctions fprintf() et printf() ont un fonctionnement analogue, mais printf() envoie toujours ses sorties dans stdout, alors que fprintf() les envoie vers un ot de sorties spci. En gnral, fprintf() est utilise pour les sorties chiers qui sont traites au Chapitre 16. La fonction printf() reoit un nombre variable darguments. Le seul et unique argument obligatoire est la chane format, qui indique printf() comment mettre en forme la sortie. Les arguments optionnels sont les variables et expressions que vous voulez afcher. Examinons ces quelques exemples simples qui vous donneront un aperu des possibilits de printf():

Linstruction printf("Hello, world!"); afche le message "Hello, world !" lcran. Dans cet exemple, printf() a un unique argument, la chane format. Cette chane est une chane littrale qui sera afche telle quelle lcran. Linstruction printf("%d", i); afche la valeur de la variable entire i lcran. La chane format ne contient que la conversion %d, qui demande printf() dafcher un seul entier dcimal. Le second argument, i, est le nom de la variable dont on veut afcher la valeur.

http://fribok.blogspot.com/

Linstruction printf("%d plus%d gal%d.", a, b, a+b); afche le message "2 + 3 gale 5" lcran (en supposant que a et b sont deux variables entires dont les valeurs sont respectivement 2 et 3). Dans cet exemple, printf() a quatre arguments : une chane format qui contient du texte littral et des commandes de conversion, deux variables et une expression dont on veut afcher les valeurs. Une ou plusieurs commandes de conversion qui indiquent printf() de quelle faon afcher une valeur appartenant la liste darguments. Une commande de conversion est constitue du signe % suivi dun ou plusieurs caractres. Des caractres qui ne font pas partie dune commande de conversion et qui seront afchs tels quels.

La chane format de printf() peut tre compose des lments suivants :

tudions en dtail la commande de conversion. Les composants qui apparaissent entre crochets sont optionnels :
%[flag] [largeur_champ] [.[precision]] [l]carac_conversion

carac conversion est la seule partie obligatoire de cette commande (en dehors de %). Le Tableau 14.5 donne la liste de ces caractres de conversion avec leur signication.
Tableau 14.5 : Les caractres de conversion des fonctions printf() et fprintf()

Caractre de conversion d, i u o x, X c e, E

Signication
Afche un entier sign en notation dcimale. Afche un entier non sign en notation dcimale. Afche un entier en notation octale non signe. Afche un entier en notation hexadcimale non signe. Utilisez x pour les sorties en minuscules et X pour les sorties majuscules. Afche un caractre (largument indique le code ASCII du caractre). Afche un nombre float ou double en notation scientique (par exemple, 123,45 est afch de cette faon : 1.234500e+002). Lafchage se fait avec six chiffres aprs la virgule, sauf si une autre prcision est indique avec lindicateur f. Utilisez e, ou E pour contrler le type de caractres de la sortie. Afche un nombre float ou double en notation dcimale (par exemple 123,45 sera afch 123.450000). Lafchage se fait avec six chiffres aprsaprs la virgule sauf si une autre prcision est indique. Utilise le format e, E ou f. Les formats e ou E sont choisis si lexposant est infrieur 3 ou suprieur la prcision (dont 6 est le dfaut. Sinon le format f est utilis). Les zros sont tronqus.

g, G

http://fribok.blogspot.com/

Tableau 14.5 : Les caractres de conversion des fonctions printf() et fprintf() (suite)

Caractre de conversion n

Signication
Rien nest afch. Largument qui correspond une commande de conversion n est un pointeur de type int. La fonction printf() attribue cette variable le nombre de caractres de la sortie. Afche une chane de caractres. Largument est un pointeur de char. Les caractres sont afchs jusquau premier caractre nul rencontr ou jusqu ce que le nombre de caractres indiqu par prcision soit atteint (par dfaut ce nombre est 32767). Le caractre nul de n nest pas afch. Afche le caractre %.

Lattribut l peut tre plac devant le caractre de conversion. Cet attribut nest disponible que pour les caractres de conversion o, u, x, X, i, d, b. Il signie que largument est de type long plutt que int. Quand cet attribut est associ aux caractres de conversion e, E, f, g et G, il signie que largument est de type double. Lindicateur de prcision est constitu du point dcimal (.) seul, ou accompagn dun nombre. Lindicateur de prcision ne sapplique quaux caractres de conversion e E f g G s. Il indique le nombre de chiffres afcher aprs la virgule, ou le nombre de caractres, sil est utilis avec s. Le point dcimal seul indique une prcision de 0. La largeur de champ indique le nombre minimum de caractres de la sortie. Cette largeur peut tre reprsente par :

Un entier dcimal ne commenant pas par 0. La sortie sera complte gauche par des blancs pour occuper la largeur de champ indique. Un entier dcimal commenant par 0. La sortie sera alors complte gauche par des zros pour occuper la largeur de champ indique. Le caractre (*). La valeur de largument suivant (qui sera de type int) sera interprte comme la largeur de champ. Par exemple, si w est une variable de type int ayant une valeur de 10, linstruction printf("%*d", w, a); afchera la valeur de a avec une largeur de champ de 10.

Si la largeur de champ nest pas spcie, ou si elle est plus petite que la sortie, elle sera ajuste la taille approprie. La dernire partie optionnelle de la chane format de printf() est le caractre de contrle qui suit le caractre %. Ces caractres sont au nombre de quatre :

La sortie sera cadre gauche plutt qu droite ; reprsente loption par dfaut.

http://fribok.blogspot.com/

+ Les nombres signs seront afchs avec leur signe (+ ou ). Un blanc signie que les nombres positifs seront prcds dun blanc. # Ce caractre ne sapplique quaux caractres de conversion x, X et o. Il indique que les nombres non nuls seront afchs avec 0X ou 0x devant (pour x et X), ou 0 pour les conversions de type o.

Vous pouvez coder la chane format de printf() de deux faons. La premire consiste la placer entre guillemets dans la liste darguments de printf(). La seconde est de la stocker en mmoire avec un caractre nul la n, et de transmettre son pointeur la fonction. Par exemple :
char *fmt = "la rponse est%f."; printf(fmt, x);

Ces instructions sont quivalentes linstruction suivante :


printf("La rponse est%f.", x);

Le Tableau 14.6 contient la liste des ordres de contrle de la chane format les plus courants (voir Chapitre 7). Lordre de contrle \n, par exemple, permet dafcher la sortie sur la ligne suivante.
Tableau 14.6 : Ordres de contrle le plus souvent utiliss

Ordre \a \b \n \t \\ \? \ \"

Signication
Sonnerie Retour arrire Retour la ligne Tabulation horizontale Antislash (backslash \) Point dinterrogation Guillemet simple Guillemet double

Avant de voir quelques exemples, nous vous mettons en garde contre une faille de scurit potentielle dans vos programmes avec printf() et fprintf(). En effet, vous ne devez jamais indiquer en premier argument (le format) une chane de caractres sur laquelle lutilisateur

http://fribok.blogspot.com/

peut avoir le contrle. En dautres termes, les deux lignes suivantes, qui afchent ce que lutilisateur vient dentrer au clavier, sont dangereuses :
fgets(buffer, sizeof(buffer), stdin); printf(buffer);

Cet exemple fonctionne mais donne lutilisateur le contrle du format et donc, sil est malveillant, bien plus... Les deux lignes prcdentes doivent tre crites par exemple ainsi :
fgets(buffer, sizeof(buffer), stdin); printf("%s", buffer);

Notez que maintenant, le format est contrl par le programme qui afchera les donnes sous forme de chane uniquement. printf() est une commande sophistique. La meilleure faon dapprendre sen servir, cest dtudier des exemples et de lexprimenter. Le programme du Listing 14.13 illustre plusieurs manires dutiliser cette fonction. Listing 14.13 : La fonction printf()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: /* Utilisation de printf(). */ #include <stdio.h> #include <stdlib.h> char char char char *m1 *m2 *m3 *m4 = = = = "Binaire"; "Decimal"; "Octal"; "Hexadecimal";

int main() { float d1 = 10000.123; int n; puts("Affichage dun nombre avec plusieurs largeurs \ de champ.\n"); printf("%5f\n", d1); printf("%10f\n", d1); printf("%15f\n", d1); printf("%20f\n", d1); printf("%25f\n", d1); puts("\n Appuyez sur Entre pour continuer..."); fflush(stdin); getchar();

28: puts("\nOn utilise * pour obtenir la largeur de champ");

http://fribok.blogspot.com/

Listing 14.13 : La fonction printf() (suite)


29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: puts("dune variable de la liste des arguments.\n"); for (n=5; n <=25; n+=5) printf("%*f\n", n, d1); puts("\n Appuyez sur Entre pour continuer..."); fflush(stdin); getchar(); puts("\nOn complte avec des zros.\n"); printf("%05f\n", d1); printf("%010f\n", d1); printf("%015f\n", d1); printf("%020f\n", d1); printf("%025f\n", d1); puts("\n Appuyez sur Entre pour continuer..."); fflush(stdin); getchar(); puts("\nAffichage en octal, decimal, et hexadecimal."); puts("On utilise # gauche des sorties octales et hex avec 0 et 0X."); puts("On utilise gauche pour justifier chaque valeur dans son champ."); puts("On affiche dabord le nom des colonnes.\n"); printf("%15s%15s%15s", m2, m3, m4); for (n = 1; n < 20; n++) printf("\n%15d%#15o%#15X", n, n, n, n); puts("\n Appuyez sur Entre pour continuer..."); fflush(stdin); getchar(); puts("\n\nOn utilise la commande de conversion%n pour compter"); puts("les caractres.\n"); printf("%s%s%s%s%n", m1, m2, m3, m4, &n); printf("\n\nLe dernier printf() a affich%d caractres.\n", n); exit(EXIT_SUCCESS); }

Affichage dun nombre avec plusieurs largeurs de champ. 10000.123047 10000.123047 10000.123047 10000.123047 10000.123047 Appuyez sur Entre pour continuer...

http://fribok.blogspot.com/

On utilise * pour obtenir la largeur de champ dune variable de la liste des arguments. 10000.123047 10000.123047 10000.123047 10000.123047 10000.123047 Appuyez sur Entre pour continuer... On complte avec des zros. 10000.123047 10000.123047 00010000.123047 0000000010000.123047 000000000000010000.123047 Appuyez sur Entre pour continuer... Affichage en octal, decimal, et hexadecimal."); On utilise # gauche des sorties octales et hex avec 0 et 0X. On utilise gauche pour justifier chaque valeur dans son champ. On affiche dabord le nom des colonnes. DcimalOctalHexadcimal 1 01 0X1 2 02 0X2 3 03 0X3 4 04 0X4 5 05 0X5 6 06 0X6 7 07 0X7 8 010 0X8 9 011 0X9 10 012 0XA 11 013 0XB 12 014 0XC 13 015 0XD 14 016 0XE 15 017 0XF 16 020 0X10 17 021 0X11 18 022 0X12 19 023 0X13 Appuyez sur Entre pour continuer... On utilise la commande de conversion%n pour compter les caractres BinaireDecimalOctalHexadecimal Le dernier printf() a affich 30 caractres.

http://fribok.blogspot.com/

Redirection des entres/sorties


Un programme qui travaille avec stdin et stdout peut utiliser une fonction du systme dexploitation appele redirection. La redirection permet :

Denvoyer les sorties de stdout dans un chier disque plutt que vers lcran. De lire les entres de stdin partir dun chier disque plutt qu partir du clavier.

La redirection nest pas code dans le programme. Vous devrez lindiquer sur la ligne de commande quand vous excuterez le programme. Avec Windows comme avec UNIX, les symboles de redirection sont : < et >. tudions tout dabord la redirection de la sortie. Reprenons votre premier programme C, "hello.c". Ce programme envoie le message Hello, world! lcran avec la fonction printf(). Vous savez maintenant que printf() envoie ses sorties dans stdout, elles peuvent donc tre rediriges. Quand vous entrez le nom du programme linvite de la ligne de commande, vous devez le faire suivre du symbole > puis du nom de la nouvelle destination :
hello > destination

Pour envoyer le message vers limprimante sur Windows, vous devez taper hello > prn (prn est le nom DOS de limprimante connecte sur le port LPT1:). Sur Unix, vous devez taper hello | lpr (il sagit dune redirection diffrente, lpr tant galement un programme). Si vous tapez hello > hello.txt, le message sera sauvegard dans le chier hello.txt. Soyez prudent lorsque vous redirigez une sortie vers un chier disque. Si le chier existe dj, les donnes quil contient seront effaces pour tre remplaces par votre sortie. Si le chier nexiste pas, il sera cr. Le symbole >> pourra aussi tre utilis pour les redirections. Il indique que si le chier destination existe dj, la sortie doit tre enregistre la suite des donnes quil contient. Le Listing 14.14 illustre la redirection. Listing 14.14 : La redirection des entres et des sorties
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: /* Exemple de redirection de stdin et stdout. */ #include <stdio.h> #include <stdlib.h> int main() { char buf[80]; lire_clavier(buf, sizeof(buf)); printf("Lentre tait:%s\n", buf); exit(EXIT_SUCCESS); }

http://fribok.blogspot.com/

Ce programme reoit une ligne du ot sdtin quil envoie dans sdtout en y ajoutant : Lentre tait:. Compilez ce programme puis excutez-le sans utiliser la redirection (ce programme sappelle List1414.c) en tapant LIST1414 sur la ligne de commande. Si vous tapez Le langageC en 21jours sur le clavier, le programme afchera :
Lentre tait: Le langageC en 21 jours

Si vous excutez le programme en utilisant la commande list1414 > test.txt avec la mme ligne de texte, rien ne sera afch lcran. Le chier test.txt a t cr sur disque, et il contient votre ligne de texte. Vous constaterez que ce chier ne contient que la ligne Lentre tait: Le langageC en 21 jours. Si vous aviez utilis la commande list1414 > prn sur Windows ou list1414 | lpr, cette ligne aurait t imprime sur limprimante.

Rediriger lentre
Examinons maintenant la redirection de lentre. Avec votre diteur, crez le chier source input.txt contenant une simple ligne de texte "William Shakespeare". Excutez ensuite le Listing 14.14 en entrant la commande :
list1414 <input.txt

Le programme nattendra pas que vous saisissiez du texte au clavier. Il va immdiatement afcher :
Lentre tait: William Shakespeare

Le ot stdin a t redirig vers le chier input.txt, la fonction fgets() de lire clavier() a donc lu une ligne de texte partir du chier plutt que du clavier. Vous pouvez rediriger les entres et les sorties en mme temps. Vous pouvez taper par exemple :
list1414 <input.txt >junk.txt

La lecture se fera partir de input.txt et le rsultat de lexcution du programme sera sauvegard dans junk.txt. Souvenez-vous que la redirection de stdin et stdout est une fonction offerte par le systme, elle est indpendante du langage C.

http://fribok.blogspot.com/

Quand utiliser fprintf()


La fonction de bibliothque fprintf() est quivalente printf(), lexception de ses sorties quelle envoie dans le ot indiqu. fprintf() est le plus souvent utilise avec les chiers disque qui sont tudis au Chapitre 16. Il existe toutefois deux autres utilisations pour cette fonction.

Le ot stderr
stderr (pour standard error) est un des ots prdnis du langage C. Les messages derreur sont envoys dans ce ot plutt que dans stdout. Ce ot est, comme stdout, connect lcran, mais de faon indpendante de celui-ci. En envoyant les messages derreur dans ce ot, on ne prend pas de risque si lutilisateur a utilis une redirection ; le message sera quand mme afch lcran :
fprintf(stderr, "une erreur sest produite.");

Vous pouvez crire une fonction pour traiter les messages derreur et lappeler en cas derreur la place de fprintf().
message_erreur("une erreur sest produite."); void message_erreur(char *msg) { fprintf(stderr, msg); }

En utilisant votre propre fonction, vous apportez de la souplesse votre code. Si vous avez besoin, dans certaines circonstances, denvoyer les messages derreur dans un chier plutt qu lcran, il sufra de modier la fonction. faire Crer des fonctions comme message erreur pour obtenir un code mieux structur et plus facile maintenir. Utiliser fprintf() pour crer des programmes qui enverront leurs sorties vers stdout, stderr ou dautres ots. ne pas faire Utiliser stderr pour une fonction autre que les messages derreur ou davertissement.

eils Cons

http://fribok.blogspot.com/

Rsum
Vous avez appris, dans ce chapitre, que C utilise des ots pour les entres/sorties des programmes. Les entres/sorties sont traites comme des squences doctets. Le langage C possde trois ots prdnis :
stdin stdout
le clavier lcran

Les entres clavier sont envoyes dans le ot stdin. En utilisant les fonctions de la bibliothque du langage C, vous pouvez lire les entres clavier caractre par caractre, ligne par ligne, ou comme des chanes et des nombres formats. Selon la fonction utilise, les caractres entrs peuvent tre stocks dans une mmoire tampon, ou tre envoys en cho sur lcran. Les sorties cran se font au travers du ot stdout. Comme les entres, les sorties peuvent tre traites caractre par caractre, ligne par ligne, ou sous forme de chanes et de nombres formats. Si votre programme utilise stdin et stdout, vous pouvez rediriger ses entres et ses sorties. Les entres peuvent provenir dun chier plutt que du clavier, et les sorties peuvent tre diriges vers un chier ou une imprimante plutt que vers lcran. Enn, vous avez dcouvert pourquoi les messages derreur devaient tre envoys dans le ot stderr plutt que dans stdout. stderr tant connect lcran de faon indpendante de stdout, lutilisateur recevra ses messages derreur mme sil a redirig les sorties du programme.

Q&R
Q Que se passera-t-il si jenvoie ma sortie vers une unit dentres ? R Le programme ne marchera pas. Si vous essayez, par exemple, dutiliser stderr avec la fonction scanf(), le programme sera compil et vous obtiendrez le chier excutable. La sortie derreur tant incapable de fournir des entres, le programme sera inoprant. Q Que se passera-t-il si je redirige un des ots standards ? R Cela pourra tre la cause de futurs problmes dans le programme. Si vous redirigez un ot, il faudra le rinitialiser sil est utilis de nouveau dans le programme. Beaucoup de fonctions dcrites dans ce chapitre utilisent les ots standard. Si vous en modiezun, vous le modiez pour tout le programme. Essayez, par exemple, dattribuer stdin stdout dans un des programmes du chapitre, et observez les rsultats.

http://fribok.blogspot.com/

Q Y a-t-il un danger utiliser des fonctions non ANSI dans un programme ? R Beaucoup de bibliothques de fonctions et certains compilateurs fournissent des fonctions trs utiles qui ne font pas partie du standard ANSI/ISO ni dun standard rpandu comme POSIX ou BSD. Si vous ne prvoyez pas de changer de compilateur, et si vos programmes nont pas tourner sur un autre matriel, il ny a aucun problme. Vous serez concern par la compatibilit ISO/ANSI ou POSIX si vous tes amen utiliser dautres compilateurs ou un autre type de matriel. Q Pourquoi ne pas utiliser fprintf() la place de printf()? R Si vous travaillez avec les ots dentres/sorties standard, utilisez printf() et scanf(). En utilisant ces fonctions simples, vous navez pas besoin de vous proccuper des autres ots.

Atelier
Cet atelier prsente un quiz destin consolider les connaissances acquises dans ce chapitre et quelques exercices pour mettre en pratique ce que vous venez dapprendre.

Quiz
1. Quest-ce quun ot ? 2. Les units suivantes sont-elles destines aux entres ou aux sorties ? a. Clavier. b) cran. c) Disque. 3. Donnez la liste des trois ots prdnis et des units qui leur sont associes. 4. Quels sont les ots utiliss par les fonctions suivantes ? a) printf(). b) puts(). c) scanf(). d) fprintf(). 5. Quelle est la diffrence entre les entres caractre de stdin qui utilisent la mmoire tampon, et celles qui ne lutilisent pas ? 6. Quelle est la diffrence entre les entres caractre de stdin qui sont recopies, et celles qui ne le sont pas ?

http://fribok.blogspot.com/

7. Pouvez-vous rcuprer plus dun caractre la fois avec la fonction ungetc()? Pouvez-vous rcuprer le caractre EOF? 8. Comment est dtermine la n de ligne quand vous utilisez les fonctions dentres ligne du C ? 9. Dans la liste suivante, quelles sont les conversions correctes ? a) "%d". b) "%4d". c) "%3i%c". d) "%q%d". e) "%%%i". f) "%9ld". 10. Quelle est la diffrence entre stderr et stdout?

Exercices
1. crivez linstruction qui afchera le message "hello, world" lcran. 2. Refaites lexercice 1 avec deux autres fonctions. 3. crivez linstruction qui lira une chane de 30 caractres au maximum et qui tronquera la ligne si elle rencontre un astrisque. 4. crivez linstruction qui afchera :
Jack demande, "quest-ce quun antislash?" Jill rpond, "cest \"

5. TRAVAIL PERSONNEL : crivez un programme utilisant la redirection pour lire un chier, compter le nombre doccurrences dans ce chier pour chaque lettre, puis afcher les rsultats lcran. 6. TRAVAIL PERSONNEL : crivez un programme qui lira les entres clavier et les reproduira sur lcran. Ce programme devra compter les lignes. Crez une cl de fonction pour sortir du programme.

http://fribok.blogspot.com/

Tour dhorizon de la Partie III

Les deux premires parties de ce livre vous ont fourni les bases du langage C. Au cours de cette troisime partie, nous allons apprendre tirer meilleur parti du langage C. Nous rassemblerons les connaissances acquises et verrons comment les mettre en pratique. Lorsque vous aurez termin les sept chapitres qui forment cette troisime partie, vous pourrez voler de vos propres ailes.

Quallez-vous voir maintenant ?


Voici les grands thmes de cette troisime partie : Le Chapitre 15 : Retour sur les pointeurs va vous permettre dapprofondir un des points les plus dlicats du C. Le Chapitre 16 : Utilisation de chiers sur disque traite dun sujet qui prend toute son importance ds quon aborde les applications relles. Les Chapitres 17, 18 et 19 : Manipulations de chanes de caractres, Retour sur les fonctions et Exploration de la bibliothque des fonctions vous bombarderont dune multitude de fonctions : de celles qui donnent au C toute sa puissance et toute sa souplesse. Au Chapitre 20, La mmoire, nous allons tudier en profondeur la gestion mmoire. Enn, le Chapitre 21, intitul Comment tirer parti du prprocesseur sera la cerise sur le gteau car, en plus de cette partie importante du langage, nous allons dcouvrir comment passer des arguments, depuis la ligne de commande jusquau programme.

http://fribok.blogspot.com/

15
Retour sur les pointeurs
Au Chapitre 9, nous vous avons prsent les notions de base concernant les pointeurs. Si nous avons insist sur ce sujet, cest parce que cest lun des domaines les plus importants du langage C. Nous allons y revenir pour tudier en particulier : Comment dclarer un pointeur vers un pointeur Comment utiliser les pointeurs avec des tableaux plusieurs dimensions Comment dclarer des tableaux de pointeurs Comment dclarer des pointeurs vers des fonctions Comment utiliser les pointeurs pour crer des listes lies pour lenregistrement des donnes

http://fribok.blogspot.com/

Pointeur vers un pointeur


Nous savons, depuis le Chapitre 9, quun pointeur est une variable numrique dont la valeur reprsente ladresse dune autre variable. Un pointeur se dclare en utilisant loprateur dindirection (*). Ainsi :
int *ptr;

dclare un pointeur appel ptr pouvant pointer vers une variable de type int. Vous pouvez utiliser loprateur dadresse (&) pour placer dans ptr ladresse dune variable particulire du type convenable (ici int) :
ptr = &x;

Par cette instruction, vous rangez dans ptr ladresse de la variable x. On dit alors que ptr pointe vers x. Au moyen de loprateur dindirection *, vous pouvez alors manipuler le contenu de cette variable x. Les deux instructions suivantes donnent la valeur 12 x:
x = 12; *ptr = 12;

Comme un pointeur est lui-mme une variable numrique, il est situ dans la mmoire de lordinateur une adresse particulire. Ds lors, rien nempche de crer un pointeur vers un pointeur, cest--dire une variable dont la valeur est ladresse dun pointeur. Voici comment :
int x = 12;/* x est une variable de type int */ int *ptr = &x;/* ptr est un pointeur vers x */ int **ptr_to_ptr = &pre; /* ptr_to_ptr est un pointeur vers un pointeur de type int */

Notez lutilisation dun double oprateur dindirection "**" lorsquon dclare un pointeur vers un pointeur. De mme, vous utiliserez cette double indirection quand vous voudrez vous rfrer au contenu de la variable de type int. Ainsi, linstruction
**ptr_to_ptr = 12;

donne, elle aussi, la valeur 12 la variable x et linstruction


printf("%d", **ptr_to_ptr);

afchera bien la valeur de x. Oublier lun des oprateurs dindirection vous conduirait une erreur, comme dans linstruction :
*ptr_to_ptr = 12;

http://fribok.blogspot.com/

qui assigne la valeur 12 ptr. La variable numrique 12 na aucun sens comme pointeur et le rsultat sera erron. Lorsque vous dclarez un pointeur vers un pointeur, on dit quil y a indirection multiple. Les relations entre une variable, un pointeur et un pointeur vers un pointeur sont illustres par la Figure 15.1. Il ny a rellement aucune limite (si ce nest celle du simple bon sens) la profondeur de cette indirection. En pratique, on dpasse rarement le niveau 2.
Figure 15.1 Illustration de la notion de "pointeur vers un pointeur"
x
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

12

ptr

1000

ptr_to_ptr

1008

quoi peuvent servir les pointeurs vers des pointeurs ? Lapplication la plus frquente est lutilisation de tableaux de pointeurs que nous tudierons plus loin, dans ce mme chapitre. Le Listing 19.5 vous en montrera, au Chapitre 19, une application.

Pointeurs et tableaux plusieurs dimensions


Au Chapitre 8, nous avons parl des relations existant entre les pointeurs et les tableaux. Le nom dun tableau non suivi de crochets reprsente un pointeur vers le premier lment de ce tableau. Il est bien plus facile dutiliser la notation avec pointeur lorsquon veut accder certains types de tableaux. Au Chapitre 8, nous nous tions limits des tableaux une seule dimension. Que se passe-t-il lorsquils ont deux dimensions et plus ? Souvenez-vous quun tableau plusieurs dimensions se dclare en indiquant la valeur de chacune de ses dimensions. Ainsi, la dclaration suivante cre un tableau de huit variables de type int, rparties en deux groupes de quatre (deux lignes de quatre colonnes, si vous prfrez) :
int multi[2][4];

http://fribok.blogspot.com/

La Figure 15.2 illustre ce dcoupage :


Figure 15.2 lments dune dcla-ration de tableau plusieurs dimensions.
4 1 2 3

int multi[2][4];

Ce qui sinterprte de la faon suivante : 1. On dclare un tableau appel multi. 2. Ce tableau contient deux lments principaux. 3. Chacun de ces deux lments contient son tour quatre lments. 4. Chacun de ces lments est de type int. Une dclaration de tableau plusieurs dimensions se lit de gauche droite (ce qui ne devrait gure bouleverser vos habitudes). En utilisant cette notion de groupe contenant des groupes (ou de tableau contenant des tableaux), on aboutit la reprsentation image de la Figure 15.3.
Figure 15.3 Un tableau deux dimensions vu comme un tableau de tableaux.
multi multi[0]

multi[1][3]

Revenons maintenant la notion de noms de tableaux considrs comme des pointeurs. Comme pour les tableaux une seule dimension, le nom dun tableau plusieurs dimensions est un pointeur vers le premier lment du tableau. Toujours avec le mme exemple du tableau multi, on peut dire que multi est un pointeur vers le premier lment dun tableau deux dimensions dclar comme int multi[2][4]. Quel est exactement le premier lment de multi? Comme il sagit dun tableau de tableaux, ce nest srement pas multi[0][0]. Cest, en ralit, multi[0], cest--dire le premier "sous-tableau" de quatre variables de type int.

http://fribok.blogspot.com/

Mais, multi[0] est-il un tableau ou un pointeur ? Si cest un pointeur, il doit bien pointer vers quelque chose. En effet, il pointe vers le premier lment de ce sous-tableau : multi[0][0]. Pourquoi multi[0] est-il un pointeur ? Souvenez-vous quun nom de tableau non suivi de crochets reprsente un pointeur vers le premier lment de ce tableau. Ici, il manque le second groupe de crochets ; on peut donc considrer que multi[0] est un pointeur. Si vos ides ne sont pas trs claires ce sujet, ne vous inquitez pas outre mesure. Cest un concept quelque peu inhabituel qui, au dbut, est difcile apprhender. Les rgles suivantes propos des tableaux n dimensions devraient vous aider y voir plus clair :

Le nom dun tableau suivi de n paires de crochets (chacune contenant naturellement un indice appropri) est un tableau de donnes. Le nom dun tableau suivi de moins de n paires de crochets est un pointeur vers un sous-tableau.

Dans notre exemple, multi est donc un pointeur, tout comme multi[0], alors que multi[0][0] est une variable numrique de type int. Voyons maintenant vers quoi pointent ces pointeurs. Le programme du Listing 15.1 dclare un tableau deux dimensions (semblable celui que nous venons dutiliser), et imprime les pointeurs et les adresses des premiers lments. Listing 15.1 : Relations entre pointeurs et tableaux plusieurs dimensions
1:/* Pointeurs et tableaux plusieurs dimensions. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int multi[2][4]; 6: 7:int main() 8:{ 9:printf("\nmulti =%p", multi); 10:printf("\nmulti[0] =%p", multi[0]); 11: printf("\n&multi[0][0] =%p\n", &multi[0][0]); 12: exit(EXIT_SUCCESS); 13:} multi = 0x8049620 multi[0] = 0x8049620 &multi[0][0] = 0x8049620

Analyse On constate que les valeurs sont bien identiques.

http://fribok.blogspot.com/

Intressons-nous maintenant la taille de ces lments. Le Listing 15.2 va nous permettre de la comparer. Listing 15.2 : Dtermination de la taille des lments
1:/* Taille dlments de tableaux plusieurs dimensions. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int multi[2][4]; 6: 7:int main() 8:{ 9: printf("\nLa taille de multi est gale %u", sizeof(multi)); 10:printf("\nLa taille de multi[0] est gale %u", 11: sizeof(multi[0])); 12: printf("\nLa taille de multi[0][0] est gale %u\n", 13: sizeof(multi[0][0])); 14:exit(EXIT_SUCCESS); 15:}

On obtient, sur un systme 32 bits, les rsultats suivants :


La taille de multi est gale 32 La taille de multi[0] est gale 16 La taille de multi[0][0] est gale 4

Analyse Ce ne sont pas les valeurs elles-mmes qui comptent, mais leur rapport. On voit clairement que multi[0][0], qui est une simple variable numrique, a une certaine taille (4octets). Le premier sous-tableau, multi[0], reprsente un groupement de quatre variables, et a donc une taille quatre fois suprieure. Le tableau multi a une taille lui permettant de contenir deux de ces sous-tableaux, soit 2 x 4 = 8 fois la taille dune variable numrique lmentaire. Le compilateur C "connat" la taille de lobjet point et en tient compte dans les calculs dadresses. Lorsque vous incrmentez un pointeur, sa valeur est augmente proportionnellement la taille de lobjet sur lequel il pointe. Ainsi, multi tant un sous-tableau de 4 lments de quatre octets chacun (longueur dun int), si on incrmente de pointeur dune unit, sa valeur numrique augmentera de 16. Si multi pointe sur multi[0], (multi+ 1) doit pointer sur multi[1]. Cest ce que montre le programme du Listing 15.3. Listing 15.3 : Arithmtique des pointeurs et tableaux plusieurs dimensions
1:/* Arithmtique des pointeurs et tableaux plusieurs dimensions. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:

http://fribok.blogspot.com/

5:int multi[2][4]; 6: 7:int main() 8:{ 9: printf("\nLa valeur de (multi) est%p", multi); 10:printf("\nLa valeur de (multi+1) est%p", (multi+1)); 11:printf("\nLadresse de multi[1] est%p\n", &multi[1]); 12:exit(EXIT_SUCCESS); 13:} La valeur de (multi) est 0x8049660 La valeur de (multi+1) est 0x8049660 Ladresse de multi[1] est 0x8049660

Analyse Si vous incrmentez multi de 1, sa valeur augmente en ralit de quatre fois la taille dune variable de type int. Dans cet exemple, multi est un pointeur vers multi[0], et multi[0] un pointeur vers multi[0][0]. Donc, multi est un pointeur vers un pointeur. Pour imprimer la valeur qui se trouve en multi[0][0], vous avez le choix entre les trois instructions suivantes :
printf("%d", multi[0][0]); printf("%d", *multi[0]); printf("%d", **multi);

Cela sapplique aux tableaux ayant plus de deux dimensions. Un tableau trois dimensions est un tableau dont les lments sont des tableaux deux dimensions. Chacun de ces derniers est, son tour, compos de tableaux une dimension. Jusquici, nous avons utilis des indices exprims par des constantes, mais rien nempche dutiliser des variables. Reprenons notre tableau multi:
int multi[2][4];

Pour dclarer un pointeur ptr pointant vers un lment de multi (cest--dire pointant vers un sous-tableau de 4 lments de type int), on peut crire :
int (*ptr)[4];

Pour quil pointe vers le premier sous-tableau, on crit :


ptr = multi;

http://fribok.blogspot.com/

Peut-tre vous interrogez-vous sur la raison dtre des parenthses dans la dclaration de ptr? Cest une question de priorit. Les crochets [] ont une plus forte priorit que loprateur dindirection *. Si nous crivions :
int *ptr[4];

nous dnirions un tableau de quatre pointeurs vers des variables de type int; ce nest pas ce que nous voulons. Comment utiliser des pointeurs vers des lments de tableaux plusieurs dimensions ? Comme sil sagissait de tableaux une seule dimension ; par exemple, pour passer ladresse dun tableau une fonction, ainsi que le montre le Listing 15.4. Listing 15.4 : Comment passer un tableau plusieurs dimensions une fonction au moyen dun pointeur
1:/* Passer un tableau plusieurs dimensions une fonction 2:au moyen dun pointeur */ 3:#include <stdio.h> 4:#include <stdlib.h> 5: 6:void printarray_1(int (*ptr)[4]); 7:void printarray_2(int (*ptr)[4], int n); 8: 9:intmain() 10: { 11:intmulti[3][4] = { { 1,2,3,4 }, 12:{ 5,6,7,8 }, 13:{ 9, 10, 11, 12 } }; 14:/* ptr est un pointeur vers un tableau de 4 int. */ 15: 16:int (*ptr)[4], count; 17: 18:/* Maintenant, ptr va pointer vers le premier 19:lment de multi. */ 20: 21:ptr = multi; 22: 23:/* A chaque tour de la boucle, ptr est incrment pour pointer 24:sur llment suivant (le sous-tableau de 4 lments). */ 25: 26:for (count = 0; count < 3; count++) 27: printarray_1(ptr++); 28: 29:puts("\n\nAppuyez sur Entre..."); 30:getchar(); 31:printarray_2(multi, 3); 32: printf("\n"); 33: exit(EXIT_SUCCESS); 34:} 35: 36:void printarray_1(int (*ptr)[4]) 37:{ 38:/* Affiche les lments dun tableau de 4 entiers. 39:p est un pointeur de type int. Il est ncessaire

http://fribok.blogspot.com/

40:de caster p pour quil soit gal ladresse 41:contenue dans ptr. */ 42: 43:int *p, count; 44:p = (int *)ptr; 45: 46:for (count = 0; count < 4; count++) 47: printf("\n%d", *p++); 48:} 49: 50:void printarray_2(int (*ptr)[4], int n) 51:{ 52:/* Affiche les lments dun tableau dentiers 53:de n groupes de 4 lments. */ 54: 55:int *p, count; 56:p = (int *)ptr; 57: 58:for (count = 0; count < (4 * n); count++) 59: printf("\n%d", *p++); 60:} 1 2 3 4 5 6 7 8 9 10 11 12 Appuyez sur Entre... 1 2 3 4 5 6 7 8 9 10 11 12

Analyse Le programme dclare un tableau dentiers, multi[3][4] aux lignes 11 13. En outre, il contient deux fonctions, printarray1() et printarray2(), qui vont nous servir afcher le tableau.

http://fribok.blogspot.com/

La premire de ces fonctions (lignes 36 48) ne reoit quun seul argument, qui est un pointeur vers un tableau de quatre entiers. Elle afche les quatre lments de ce tableau. La premire fois, main() appelle printarray1() la ligne 27 en lui passant un pointeur vers le premier lment (le premier sous-tableau de 4 entiers) de multi. Elle appelle ensuite printarray1() deux autres fois en auto-incrmentant simplement ptr qui, ds lors, va pointer successivement sur le deuxime sous-tableau puis sur le troisime. la suite de ces trois appels, la totalit de multi aura t afche. La seconde fonction printarray2() utilise une approche diffrente. Elle reoit, elle aussi, un pointeur vers un tableau de quatre entiers mais, en outre, un entier lui indique le nombre de ces tableaux contenus dans multi. Avec un seul appel (ligne 32), printarray2() va afcher la totalit de multi. Les deux fonctions mettent en pratique la notation des pointeurs pour avancer dans les lments du tableau. La notation (* int) ptr utilise dans les deux fonctions (lignes 43 et 55) ne vous semble peut-tre pas assez claire. Il sagit dun casting (dune coercition, comme on dit parfois en franais) qui change temporairement le type des donnes de la variable, les faisant passer du type dclar un nouveau type. Il est ncessaire ici, parce que ptr et p sont des pointeurs de type diffrent (p est un pointeur vers un int, alors que ptr est un pointeur vers un tableau de quatre int). Tout se passe comme si on disait au compilateur "Pour cette instruction, tu vas considrer que ptr est un pointeur vers un int". Nous reviendrons sur la coercition au Chapitre 20. ne pas faire Oublier dutiliser un double oprateur dindirection (**) lorsquon dclare un pointeur vers un pointeur. Oublier quun pointeur sincrmente en fonction de la taille de lobjet sur lequel il pointe. Oublier dutiliser des parenthses lorsquon dclare un processus vers un tableau. Pour dclarer un pointeur vers un tableau de caractres, utilisez la forme suivante :
char (*lettres)[26];

eils Cons

Pour dclarer un tableau de pointeurs vers des caractres, utilisez :


char *lettres[26];

http://fribok.blogspot.com/

Tableaux de pointeurs
Nous avons vu au Chapitre 8 quun tableau est une collection dadresses de rangement de mme type, auxquelles on se rfre sous le mme nom. Comme, en C, les pointeurs constituent un type de donnes, il ny a aucune raison pour quon ne puisse pas constituer des tableaux de pointeurs. Lusage le plus frquent de ce type de construction concerne les chanes de caractres. Comme vous lavez appris au Chapitre 10, une chane de caractres est une suite de caractres rangs en mmoire. Le dbut de la chane est indiqu par un pointeur vers le premier caractre (un pointeur de type char, naturellement) et la n de la chane est marque par le caractre NULL. En dclarant et en initialisant un tableau de pointeurs vers des types char, vous pouvez accder un grand nombre de chanes et les manipuler. Chaque lment du tableau pointe en effet sur une chane diffrente, il suft donc de boucler sur ce tableau pour y accder tour tour.

Chanes et pointeurs rvision


Cest le moment de revoir quelques-unes des notions abordes au Chapitre 10 concernant lallocation des chanes et leur initialisation. Pour allouer et initialiser une chane, vous devez dclarer un tableau de type char de la faon suivante :
char message[] = "Ceci est un message";

ou bien, en utilisant un pointeur :


char *message = "Ceci est un message";

Les deux dclarations sont quivalentes. Dans les deux cas, le compilateur alloue assez de place pour contenir la chane et son terminateur ; message est un pointeur vers le dbut de la chane. Que pensez-vous, maintenant, des deux instructions suivantes ?
char message1[20]; char *message2;

La premire instruction dclare un tableau de type char ayant une longueur de vingt caractres ; message1 est alors un pointeur vers le dbut de ce tableau. La place a t alloue, mais rien ny a t rang : la chane nest pas initialise. La seconde instruction dclare un pointeur de type char, message2, et cest tout. Aucune place na t rserve et, a fortiori, rien na t initialis. Pour crer une chane de caractres sur laquelle message2 pointerait, vous devez commencer par allouer de la mmoire pour la chane. Au Chapitre 10, vous avez appris utiliser pour cela la fonction malloc().

http://fribok.blogspot.com/

Souvenez-vous quil faut allouer de la place pour toute chane, soit la compilation, soit lexcution, avec une fonction de type malloc().

Tableau de pointeurs de type char


Maintenant que vous avez bien en tte ces notions, comment allez-vous dclarer un tableau de pointeurs ? Linstruction suivante dclare un tableau de dix pointeurs de type char:
char *message[10];

Chaque lment du tableau message[] est un pointeur individuel de type char. Comme vous lavez sans doute devin, vous pouvez associer la dclaration et linitialisation :
char message[10] = {"un", "deux", "trois"};

Voici les effets de cette dclaration :

Elle alloue un tableau de dix lments appel message, chaque lment du message tant un pointeur de type char. Elle alloue de la place quelque part en mmoire (peu importe o) et y place des chanes dinitialisation avec, pour chacune, un terminateur NULL. Elle initialise message[0] pour quil pointe sur le premier caractre de la chane 1, message[1] pour quil pointe sur le premier caractre de la chane 2 et message[2], pour quil pointe sur le premier caractre de la chane 3.

Cest ce quillustre la Figure 15.4, sur laquelle on voit les relations existant entre le tableau de pointeurs et les chanes de caractres. Notez que, dans cet exemple, les lments message[3] message[9] ne sont pas initialiss et ne pointent donc sur rien du tout.
Figure 15.4 Un tableau de pointeurs de type char.
message[0] 1000 message[1] 1556 message[2] 2012 message[3] ? message[4] ? message[5] ? message[6] ? message[7] ? message[8] ? message[9] ?
1000

o n e \0
1556

t w o \0
2012

t h r e e \0

Portons maintenant notre attention sur le Listing 15.5 qui montre un exemple dutilisation dun tableau de pointeurs.

http://fribok.blogspot.com/

Listing 15.5 : Initialisation et utilisation dun tableau de pointeurs de type char


1:/* Initialisation dun tableau de pointeurs de type char. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int main() 6:{ 7:char *message[8] = {"Lorsque", "lenfant", "parat,", "le", 8:"cercle", "de", "famille", "sagrandit."}; 9:int count; 10: 11:printf("\n"); 12:for (count = 0; count < 8; count++) 13: printf("%s ", message[count]); 14:printf("\n"); 15:exit(EXIT_SUCCESS); 16:} Lorsque lenfant parat, le cercle de famille sagrandit.

Analyse Dans le programme, on dclare un tableau de huit pointeurs de type char initialiss pour quils pointent sur 8 chanes reproduisant, peu de chose prs, un vers de Victor Hugo (lignes 7 et 8). Une boucle for (lignes 12 et 13) afche les lments du tableau en intercalant un espace entre chacun deux. Vous voyez que la manipulation des tableaux de pointeurs est plus facile que celle des chanes elles-mmes. Cet avantage est vident dans des programmes plus compliqus comme celui qui va vous tre prsent dans ce chapitre, et dans lequel on appelle une fonction. Il est, en effet, bien plus facile de passer un pointeur une fonction que de lui passer plusieurs chanes. Ce programme (Listing 15.6) est une rcriture du programme prcdent dans lequel lafchage se fait en appelant une fonction. Listing 15.6 : Passer un tableau de pointeurs une fonction
1:/* Passer un tableau de pointeurs une fonction. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:void print_strings(char *p[], int n); 6: 7:int main() 8:{ 9:char *message[8] = {"Lorsque", "lenfant", "parat,", "le", 10:"cercle", "de", "famille", "sagrandit."}; 11:

http://fribok.blogspot.com/

Listing 15.6 : Passer un tableau de pointeurs une fonction (suite)


12:print_strings(message, 8); 13:exit(EXIT_SUCCESS); 14:} 15:void print_strings(char *p[], int n) 16:{ int count; 17: 18:for (count = 0; count < n; count++) 19: printf("%s ", p[count]); 20:printf("\n"); 21:} Lorsque lenfant parat, le cercle de famille sagrandit.

Analyse Comme on peut le voir la ligne 15, la fonction print strings() demande deux arguments : le premier est un tableau de pointeurs de type char et le second, le nombre dlments afcher. Rien de plus signaler. Vers le dbut de cette section, nous vous avions annonc une dmonstration ultrieure. Eh bien, vous venez de lavoir (et de la voir !).

Un exemple
Il est grand temps, maintenant, de passer quelque chose de plus compliqu. Le programme du Listing 15.7 met en uvre plusieurs des notions dj tudies dont, en particulier, les tableaux de pointeurs. Lutilisateur tape des lignes de texte au clavier, le programme les range en mmoire et en garde une trace grce un tableau de pointeurs. Lorsque lutilisateur tape une ligne vierge, le programme trie les lignes entres et les afche lcran. Voici larchitecture de ce programme, vu sous langle de la programmation structure : 1. Lire des lignes au clavier, une par une, jusqu rencontrer une ligne vierge. 2. Trier les lignes en ordre alphabtique ascendant. 3. Afcher les lignes tries. Cette liste suggre lcriture de trois fonctions distinctes, une pour chaque tche. Elles sappelleront respectivement get lines(), sort() et print strings(). La premire, get lines(), peut se dcomposer ainsi : 1. Garder une trace du nombre de lignes entres par lutilisateur et renvoyer cette valeur au programme appelant, une fois toutes les lignes entres.

http://fribok.blogspot.com/

2. Limiter le nombre de lignes pouvant tre tapes par lutilisateur, en xant par avance un maximum. 3. Allouer de la place en mmoire pour chaque ligne. 4. Constituer un tableau de pointeurs contenant les adresses des lignes entres par lutilisateur. 5. Revenir au programme appelant si lutilisateur tape une ligne vierge. La deuxime, sort(), est une fonction de tri trs simplie avec laquelle on balaye le tableau des lignes entres, en partant de la premire et en effectuant des permutations. la n du premier balayage, la plus petite (par le code des caractres et non par le nombre de caractres taps) se retrouve en tte. On part ensuite de la deuxime ligne et on trie le tableau en la comparant aux n 2 lignes restantes. la n de ce balayage, les deux plus petites lignes sont en place. On continue ainsi jusqu ce quil ne reste plus quune seule ligne, qui est forcment la plus grande. Cest sans doute mthode de tri la plus lente mais, en raison de la simplicit de son algorithme, elle est presque aussi clbre que "Hello, world" ou "Bonjour le monde". Notez que, en ralit, ce ne sont pas les lignes quon permute, mais les pointeurs sur les lignes. Vous verrez, au Chapitre 19, que la bibliothque standard C contient une fonction bien plus labore et bien plus rapide, qsort(). Mais, pour un exemple aussi court que celui-ci, notre mthode est sufsante. La dernire fonction, print strings(), existe dj : nous venons de la rencontrer dans le Listing 15.6. Listing 15.7 : Tri et afchage dun groupe de lignes entres au clavier
1:/* Lutilisateur tape une suite de phrases au clavier, elles 2:sont tries puis affiches lcran. */ 3: 4:#include <stdio.h> 5:#include <string.h> 6:#include <stdlib.h> 7: 8:#define MAXLINES 25/* pas plus de 25 phrases */ 9: 10:int get_lines(char *lines[]);/* entre des phrases */ 11:void sort(char *p[], int n);/* tri des phrases */ 12:void print_strings(char *p[], int n); /* raffichage lcran */ 13: 14:char *lines[MAXLINES]; 15: 16:int main() 17:{ 18:int number_of_lines;

http://fribok.blogspot.com/

Listing 15.7 : Tri et afchage dun groupe de lignes entres au clavier (suite)
19: 20:/* Lire les phrases au clavier. */ 21: 22:number_of_lines = get_lines(lines); 23: 24:if (number_of_lines < 0) 25:{ puts("Erreur dallocation mmoire"); 26:exit(EXIT_FAILURE); 27:} 28: 29:sort(lines, number_of_lines); 30:print_strings(lines, number_of_lines); 31:return(0); 32:} 33: 34:int get_lines(char *lines[]) 35:{ int n = 0; 36:char buffer[80];/* Mmoire de stockage temporaire */ 37: 38:puts("Tapez les phrases une par une."); 39:puts("Terminez par un simple appui sur Entre."); 40: 41:while ((n < MAXLINES) && 42:(lire_clavier(buffer, sizeof(buffer))!= 0)) 43:{ if ((lines[n] = malloc(strlen(buffer)+1)) == NULL) 44: return 1; 45:strcpy(lines[n++], buffer); 46:} 47:return n; 48: 49:} /* Fin de get_lines() */ 50: 51:void sort(char *p[], int n) 52:{ int a, b; 53:char *x; 54: 55:for (a = 1; a < n; a++) 56:for (b = 0; b < n1; b++) 57:{ if (strcmp(p[b], p[b+1]) > 0) 58:{ x = p[b]; 59:p[b] = p[b+1]; 60:p[b+1] = x; 61:} 62:} 63:}/* Fin de sort() */ 64: 65:void print_strings(char *p[], int n) 66:{ int count; 67: 68:for (count = 0; count < n; count++) 69: printf("%s\n ", p[count]); 70:}/* Fin de print_strings() */

http://fribok.blogspot.com/

Voici un exemple de ce que lon peut obtenir :


Tapez les phrases une par une. Terminez par un simple appui sur Entre. chien ordinateur assiette jeu fourchette zoo assiette chien fourchette jeu ordinateur zoo

Analyse Nous allons examiner quelques dtails de ce programme dans lequel on voit apparatre de nouvelles fonctions, et, en particulier, le chier den-tte string.h qui contient les prototypes des fonctions de manipulation de chanes de caractres. Dans la fonction get lines(), lentre des lignes est contrle par les instructions des lignes 41 et 42 qui testent deux conditions : on na pas dpass le nombre de lignes maximum (MAXLINES), et lire clavier() na pas renvoy 0 (chane vide). Lorsquune ligne a t lue au clavier, il faut allouer de la place pour la ranger. Cest ce que fait linstruction de la ligne 43 :
if ((lines[n] = malloc(strlen(buffer)+1)) == NULL)

La place en mmoire est alloue dynamiquement par un appel la fonction malloc(). La longueur de la chane est majore de 1 pour tenir compte du terminateur. La fonction renvoie un pointeur qui est rang en lines[n] sil est diffrent de NULL. Cette dernire valeur indiquerait quil ny a plus de mmoire disponible. On reviendrait alors au programme appelant avec une valeur gale 1, ce dernier afcherait "Erreur dallocation mmoire" la ligne 25 et se terminerait immdiatement. Si lallocation de mmoire a russi, le programme recopie la chane lue (pointe par buffer) dans la zone alloue en appelant la fonction de bibliothque strcpy(). Ensuite, la boucle se rpte.

http://fribok.blogspot.com/

Le lecteur attentif ne manquera pas de remarquer que, si lallocation dynamique de mmoire est correctement effectue, les auteurs ont malheureusement oubli de restituer cette mmoire (avec laide de la fonction free()) avant de mettre n au programme. Le lecteur pourra admettre que cet oubli tait destin veiller sa sagacit. Quant au tri, nous avons esquiss son algorithme plus haut et la fonction sort() ne fait que le mettre en application. La Figure 15.5 montre la faon dont se prsentent les pointeurs avant le dbut du tri. On remarque que, lors de la premire passe, si on a lu n lignes, on va faire n 1 comparaisons ; quon en fera n 2 lors de la seconde passe ; et ainsi de suite jusqu la n, o la dernire ligne sera automatiquement en place. Les permutations de pointeurs vers les chanes se font par les instructions des lignes 58 60. Si les deux chanes sont gales, on les laisse en place. la n du tri, les pointeurs peuvent se trouver (et ce sera gnralement le cas, sauf si les phrases taient dj dans le bon ordre) bouleverss (voir Figure 15.6).
Figure 15.5 Les pointeurs avant le tri.
lines[0] lines[1] lines[2] lines[3] lines[4] d o g \0 a p p l e \0 z o o \0 p r o g r a m \0 m e r r y \0

Figure 15.6 Les pointeurs aprs le tri.


lines[0] lines[1] lines[2] lines[3] lines[4]

d o g \0 a p p l e \0 z o o \0 p r o g r a m \0 m e r r y \0

Pointeurs vers des fonctions


Les pointeurs vers des fonctions offrent un autre moyen dappeler des fonctions. Il y a l de quoi vous surprendre puisquun pointeur reprsente gnralement ladresse dune variable. Cela nest pas tout fait exact. Il faudrait dire "ladresse dun objet C". Et une fonction EST un objet C. Elle se trouve quelque part en mmoire et son adresse est donc connue (sinon, comment ferait-on pour lappeler ?).

http://fribok.blogspot.com/

Pourquoi peut-on avoir besoin dutiliser un pointeur vers une fonction ? Tout simplement pour permettre dappeler une "fonction va", cest--dire une fonction ou une autre, selon tel ou tel critre. Le nom de la fonction appeler est alors pass sous forme de pointeur vers la fonction choisie.

Dclaration dun pointeur vers une fonction


Comme pour les variables, un pointeur vers une fonction doit tre dclar. La forme gnrale de ce type de dclaration est la suivante :
type (*ptr_vers_fonction)(liste_d_arguments);

Cela signie quon dclare un pointeur appel ptr vers fonction qui renvoie un rsultat type et admet les arguments numrs dans liste d arguments. Voici quelques exemples de dclarations :
int (*fonc1)(int x); void (*fonc2)(double y, double z); char (*fonc3)(char *p[]); void (*fonc(4));

La premire dclaration dclare fonc1 comme tant un pointeur vers une fonction de type int acceptant un argument de type int. Dans la deuxime, fonc2 est un pointeur vers une fonction de type void acceptant deux arguments de type double, tandis que pour la troisime, fonc3 est un pointeur vers une fonction de type char acceptant un argument qui est un tableau de pointeurs de type char. Enn, dans la dernire, fonc4 est un pointeur vers une fonction de type void sans argument. Le nom de la fonction doit tre plac entre parenthses pour des raisons lies la priorit de loprateur dindirection *. Oublier ces parenthses conduirait de srieux problmes.

Initialisation et utilisation dun pointeur vers une fonction


Un pointeur vers une fonction doit naturellement tre dclar comme tout pointeur mais, en outre, il doit tre initialis an de pointer vers une fonction. Les arguments et la valeur de retour de cette fonction doivent correspondre ce qui a t dclar dans le prototype de la dclaration du pointeur. Voici un exemple :
float carre(float z);/* prototype de la fonction */ float (*p) (float x);/* dclaration du pointeur */ float carre(float x);/* la fonction elle-mme */ { return x * x; }

http://fribok.blogspot.com/

On peut maintenant crire, par exemple :


p = carre; reponse = p(x);

Cest simple mais, pour linstant, on ne voit pas trs bien quoi a peut servir. (Patience, le programme du Listing 15.9 clairera votre lanterne !) Le Listing 15.8 en montre une application directe. Listing 15.8 : Utilisation dun pointeur vers une fonction pour appeler une fonction
1:/* Utilisation dun pointeur vers une fonction pour appeler une 2:fonction. */ 3:#include <stdio.h> 4:#include <stdlib.h> 5:double square(double x);/* prototype de la fonction. */ 6:double (*p)(double x);/* dclaration du pointeur. */ 7: 8:int main() 9:{ p = square;/* p pointe vers square() */ 10: 11:/* Appel de square() de deux faons. */ 12:printf("%f%f\n", square(6.6), p(6.6)); 13:exit(EXIT_SUCCESS); 14:} 15:double square(double x)/* la fonction square() elle-mme. */ 16:{ return x * x; 17:} 43.55999943.559999

Analyse Rien ajouter : cest la transcription exacte de lexemple prcdent. Comme pour les pointeurs vers des variable numriques, rappelons quun nom de fonction sans parenthses est un pointeur vers la fonction en question. Lintrt dutiliser un pointeur spar est de pouvoir modier son contenu ; donc la dsignation de lobjet sur lequel il pointe, ce qui nest pas possible autrement. Le programme du Listing 15.9 appelle une fonction qui va elle-mme appeler une fonction diffrente selon largument qui lui aura t pass. Chacune des trois fonctions possibles afche un message particulier.

http://fribok.blogspot.com/

Listing 15.9 : Utilisation dun pointeur vers une fonction pour choisir entre plusieurs fonctions appeler
1:/* Utilisation dun pointeur pour appeler diffrentes fonctions.*/ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5: /* prototypes des fonctions. */ 6:void func1(int x); 7:void one(void); 8:void two(void); 9:void other(void); 10: 11:int main() 12:{ int a; 13: 14:for (;;) 15:{ puts("\nTapez un entier compris entre 1 et 10, 0 pour quitter"); 16:scanf("%d", &a); 17:if (a == 0) break; 18:func1(a); 19:} 20: exit(EXIT_SUCCESS); 21:} 22:void func1(int x) 23:{ void (*ptr)(void); 24: 25:if (x == 1) ptr = one; 26:else if (x == 2) ptr = two; 27:else ptr = other; 28: 29:ptr(); 30:} 31: 32:void one(void) 33:{ puts("Vous avez tap 1"); 34:} 35: 36:void two(void) 37:{ puts("Vous avez tap 2"); 38:} 39: 40:void other(void) 41:{ puts("Vous navez tap ni 1 ni 2"); 42:} Tapez un entier compris entre 1 et 10, 0 pour quitter 1 Vous avez tap 1 Tapez un entier compris entre 1 et 10, 0 pour quitter 2

http://fribok.blogspot.com/

Vous avez tap 2 Tapez un entier compris entre 1 et 10, 0 pour quitter 3 Vous navez tap ni 1 ni 2 Tapez un entier compris entre 1 et 10, 0 pour quitter 0

Analyse La boucle innie for de la ligne 14 lit une valeur tape au clavier et appelle la fonction func1() si cette valeur nest pas nulle (on se demande dailleurs pourquoi avoir demand lutilisateur de limiter son choix entre 1 et 10). Si la valeur lue est nulle, le programme sarrte. Dans cette fonction, on commence par dclarer un pointeur vers une fonction (ptr). Selon la valeur passe la fonction, ce pointeur est initialis avec les noms one, two ou other. la ligne 29, on appelle tout simplement ptr(). Selon la valeur passe en argument func1(), cela permettra dappeler une des trois fonctions one(), two() ou other(). Le programme du Listing 15.10 est une version modie du prcdent : Listing 15.10 : Nouvelle version du programme du Listing 15.9
1:/* Passer un pointeur vers une fonction en argument */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:#define TOUJOURS 1 6: 7:/* prototypes des fonctions */ 8:void func1(void (*p)(void)); 9:void one(void); 10:void two(void); 11:void other(void); 12: 13:int main() 14:{ void (*ptr)(void);/* pointeur vers une fonction */ 15:inta; 16: 17:while(TOUJOURS) 18:{ puts("\nTapez un entier positif; 0 pour terminer."); 19:scanf("%d", &a); 20: 21:if (a == 0) break; 22:else if (a == 1)ptr = one; 23:else if (a == 2)ptr = two; 24:else ptr = other; 25:

http://fribok.blogspot.com/

26:func1(ptr); 27:} 28: exit(EXIT_SUCCESS); 29:} 30:void func1(void (*p)(void)) 31:{ p(); 32:} 33: 34:void one(void) 35:{ puts("Vous avez tap 1"); 36:} 37: 38:void two(void) 39:{ puts("Vous avez tap 2"); 40:} 41: 42:void other(void) 43:{ puts("Vous navez tap ni 1 ni 2"); 44:} Tapez un entier positif; 0 pour terminer. 34 Vous navez tap ni 1 ni 2 Tapez un entier positif; 0 pour terminer. 2 Vous avez tap 2 Tapez un entier positif; 0 pour terminer. 1 Vous avez tap 1 Tapez un entier positif; 0 pour terminer. 0

Analyse Les diffrences avec le programme prcdent sont minimes. Dabord, nous avons prfr une boucle while portant sur une expression diffrente de zro (la constante TOUJOURS), ce qui est la fois plus lgant et plus lisible. Ensuite, ce nest plus func1() qui effectue la slection de la fonction appeler mais, directement, la fonction main() qui va passer func1() le pointeur vers la fonction appeler quelle vient dinitialiser. Enn, nous avons supprim la restriction du nombre taper dont nous avions signal linutilit dans la version prcdente. Revenons maintenant au programme du Listing 15.7. Lordre de tri est dtermin par les valeurs de retour renvoyes par la fonction de comparaison appele par qsort(). Celle-ci

http://fribok.blogspot.com/

exploite la fonction de bibliothque strcmp(). An de pouvoir trier dans le sens ascendant ou dans le sens descendant, nous allons crire deux fonctions de tri, lune dans le sens normal (alpha()), lautre dans le sens oppos (reverse()) :
/* Comparaison en ordre ascendant */ int alpha(char *p1, char *p2) { return(strcmp(p2, p1)); } /* Comparaison en ordre descendant */ int reverse(char *p1, char *p2) { return(strcmp(p1, p2)); }

Remarquons lastuce utilise pour obtenir une slection dans lordre alphabtique inverse : on sest content de renverser lordre de comparaison et, au lieu de comparer la premire chane la seconde, on compare la seconde la premire. Le choix entre ces deux fonctions sera effectu par lutilisateur. On aboutit ainsi au programme du Listing 15.11 : Listing 15.11 : Programme de tri dans un sens ou dans lautre
1:/* Tri dune suite de lignesde texte. */ 2: 3:#include <stdio.h> 4:#include <string.h> 5:#include <stdlib.h> 6: 7:#define MAXLINES 25 8: 9:int get_lines(char *lines[]); 10:void sort(char *p[], int n, int sort_type); 11:void print_strings(char *p[], int n); 12:int alpha(char *p1, char *p2); 13:int reverse(char *p1, char *p2); 14: 15:char *lines[MAXLINES]; 16: 17:int main() 18:{ int number_of_lines, sort_type; 19: 20:/* Lire les lignesau clavier */ 21: 22:number_of_lines = get_lines(lines); 23: 24:if (number_of_lines < 0) 25:{ puts("Erreur dallocation mmoire"); 26:exit(EXIT_FAILURE); 27:}

http://fribok.blogspot.com/

28: 29:printf("Tapez 0 pour trier en ordre alphabtique inverse,\n"); 30:printf("ou 1, pour trier en ordre alphabtique direct: "); 31:scanf("%d", &sort_type); 32: 33:sort(lines, number_of_lines, sort_type); 34:print_strings(lines, number_of_lines); 35: exit(EXIT_SUCCESS); 36:} 37: 38:int get_lines(char *lines[]) 39:{int n = 0; 40:char buffer[80]; /* Zone de lecture pour chaque ligne*/ 41: 42:puts("Tapez les lignesune par une; une lignevierge \ 43:pour terminer"); 44:while (n < MAXLINES && lire_clavier(buffer, sizeof(buffer))!= 0) 45:{ if ((lines[n] = malloc(strlen(buffer)+1)) == NULL) 46: return 1; 47: strcpy(lines[n++], buffer); 48:} 49: 50:return n; 51: 52:} /* Fin de get_lines() */ 53: 54:void sort(char *p[], int n, int sort_type) 55:{int a, b; 56:char *x; 57: 58:int (*compare)(char *s1, char *s2); 59:/* ptr vers fonctionde comparaison*/ 60:/* Initialiser le pointeur pour quil pointe sur la fonction 61:de comparaison appeler selon largument pass */ 62: 63:compare = (sort_type)? reverse: alpha; 64: 65:for (a = 1; a < n; a++) 66:for (b = 0; b < n1; b++) 67:{ if (compare(p[b], p[b+1]) > 0) 68:{ x = p[b]; 69:p[b] = p[b+1]; 70:p[b+1] = x; 71:} 72:} 73:} /* Fin de sort() */ 74: 75:void print_strings(char *p[], int n) 76:{ int count; 77:

http://fribok.blogspot.com/

Listing 15.11 : Programme de tri dans un sens ou dans lautre (suite)


78:for (count = 0; count < n; count++) 79:printf("%s\n ", p[count]); 80:} 81: 82:int alpha(char *p1, char *p2) /* Comparaison en ordre ascendant */ 83:{ return(strcmp(p2, p1)); 84:} 85: 86:int reverse(char *p1, char *p2) /* Comparaison en ordre descendant */ 87:{ return(strcmp(p1, p2)); 88:} Tapez les lignesune par une; une lignevierge pour terminer piano bretelles prunier hortensia abricotier pommier hortensia trombone coulisse Tapez 0 pour trier en ordre alphabtique inverse, ou 1, pour trier en ordre alphabtique direct: 0 trombone coulisse prunier pommier piano bretelles hortensia hortensia abricotier Tapez les lignesune par une; une lignevierge pour terminer piano bretelles prunier hortensia abricotier pommier hortensia trombone coulisse Tapez 0 pour trier en ordre alphabtique inverse, ou 1, pour trier en ordre alphabtique direct: 1 abricotier hortensia hortensia piano bretelles pommier prunier trombone coulisse

http://fribok.blogspot.com/

Analyse la diffrence du Listing 15.7, un pointeur est dclar vers la fonction de comparaison dans la fonction sort():
int (*compare)(char *s1, char *s2);

Ce pointeur est ensuite initialis de la faon suivante :


compare = (sort_type)? reverse: alpha;

au moyen de loprateur ternaire (les parenthses autour de sort type ne sont pas vraiment ncessaires). Il pointera donc soit vers alpha(), soit vers reverse(), selon la valeur de lentier sort type pass en argument. Dans les deux boucles for de balayage du tableau de pointeurs, la comparaison de deux lignes seffectuera ainsi :
if (compare(p[b], p[b+1]) > 0)

Ici, pas plus que dans le Listing 15.7, on ne libre les zones de mmoire alloues dynamiquement au tableau des pointeurs.
eils Cons

faire Mettre en pratique la programmation structure. Initialiser un pointeur avant de lutiliser. Librer les zones de mmoire alloues dynamiquement ! ne pas faire Ne pas mettre des parenthses aux bons endroits quand on dclare un pointeur vers une fonction. Voici deux exemples diffrents : Dclaration dun pointeur vers une fonction sans argument et qui retourne un caractre :
char (*fonc)();

Dclaration dune fonction qui retourne un pointeur vers un caractre :


char *fonc();

Utiliser un pointeur vers une fonction qui aurait t dclar avec un type de retour diffrent ou des arguments diffrents de ce que vous allez rellement utiliser.

http://fribok.blogspot.com/

Les listes chanes


Une liste chane est une mthode denregistrement des donnes que lon peut facilement implmenter avec le langage C. Nous traitons ce sujet dans un chapitre consacr aux pointeurs parce que ces derniers constituent un lment trs important des listes chanes. Il existe plusieurs sortes de listes chanes : les listes chanes simples, les listes chanes doubles, les arbres binaires... Chacun de ces types convient plus particulirement certaines tches. Le point commun est que les liens entre les articles sont explicites et dnis par des informations places dans les articles eux-mmes. Cest l une diffrence essentielle par rapport aux tableaux, dans lesquels les liens entre les articles sont implicites, et rsultent de lagencement gnral du tableau. Dans ce chapitre, nous allons expliquer les listes chanes simples (que lon appellera listes chanes).

Principes de base des listes chanes


Chaque lment de donne dune liste chane appartient une structure (voir Chapitre 11). Celle-ci contient les lments de donnes requis pour enregistrer les donnes spciques dun programme. Cette structure contient un lment de donne supplmentaire : un pointeur qui fournit les liens de la liste chane. Voici un exemple simple :
struct person { char name[20]; struct person *next; };

Ces lignes de code dnissent la structure person. La partie donnes nest constitue que dun tableau de caractres de vingt lments. Lutilisation dune liste chane ne simpose pas pour des donnes aussi simples, le seul intrt de ces lignes est de constituer un exemple. La structure person contient aussi un pointeur de type person, il sagit donc dun pointeur vers une autre structure de mme type. Cela signie quune structure de type person contient un ensemble de donnes, et quelle peut aussi pointer vers une autre structure person. La Figure 15.7 prsente le chanage des structures dans une liste.
Donnes pointeur suivant Donnes pointeur suivant Donnes pointeur suivant NULL

Figure 15.7 tablissement du chanage entre les lments dune liste chane.

Remarquez que dans la Figure 15.7, chaque structure person pointe sur la structure person suivante. La dernire ne pointe sur rien. Pour concrtiser ce fait, on donne son pointeur la valeur NULL.

http://fribok.blogspot.com/

Info

Les structures constituant une liste chane sont appeles liens, nuds, ou lments dune liste chane.

Nous avons vu comment identier le dernier lment dune liste chane. Vous accdez au premier lment par lintermdiaire dun pointeur de tte, et cet lment contient un pointeur vers le deuxime. Ce deuxime lment contient un pointeur vers le troisime, et ainsi de suite jusqu ce que le pointeur rencontr ait la valeur NULL. Si la liste est vide (sans aucun lien), cest le pointeur de tte qui a la valeur NULL. La Figure 15.8 prsente ce pointeur de tte lors de linitialisation de la liste, puis aprs lajout du premier lment.
Figure 15.8 Le pointeur de tte dune liste chane.
Pointeur de tte Pointeur de tte

NULL

donnes

NULL Avant la premire addition Aprs la premire addition

Info

Le pointeur de tte est un pointeur vers le premier lment dune liste. On le dsigne parfois sous le nom de "pointeur vers le sommet de la liste".

Utiliser les listes chanes


Une liste chane, cest un peu comme un chier disque : des maillons peuvent tre ajouts, modis ou supprims, mais il est indispensable dajuster les pointeurs de liaison (de chanage) lorsquon excute ce type dopration. Vous trouverez dans la suite de ce chapitre, un exemple de liste chane simple puis un programme plus complexe. Cependant, avant dexaminer le code, nous allons tudier quelques oprations indispensables la manipulation des listes chanes en utilisant la structure person prsente plus haut.

Prliminaire
Pour commencer une liste chane, vous devez dnir une structure de donnes et le pointeur de tte. Ce pointeur doit tre initialis avec la valeur nulle puisque la liste est vide au moment de sa cration. Vous aurez besoin dun pointeur supplmentaire vers le type de structure de la liste pour pouvoir ajouter des enregistrements (vous verrez plus loin que des pointeurs supplmentaires pourront tre ncessaires). Voici comment procder :
struct person { char name[20];

http://fribok.blogspot.com/

struct person *next; }; struct person *new; struct person *head; head = NULL;

Ajouter le premier maillon


Si le pointeur de tte a la valeur NULL, la liste est vide et le nouveau maillon sera lunique lment de la liste. Si ce pointeur a une valeur diffrente, la liste contient dj un ou plusieurs lments. Dans tous les cas, la procdure pour ajouter un maillon est identique : 1. Crez une structure en utilisant malloc() pour allouer la mmoire ncessaire. 2. Dnissez le pointeur du nouvel lment avec la valeur du pointeur de tte. Cette valeur sera nulle si la liste est vide ou gale ladresse du premier lment en cours. 3. Modiez la valeur du pointeur de tte avec ladresse du nouvel lment. Voici le code correspondant :
new = malloc(sizeof(struct person)); new->next = head; head = new

ntion Atte

Il est capital deffectuer les oprations dans lordre indiqu, sinon, on perdrait le pointeur vers lancien premier maillon.

La Figure 15.9 prsente lajout dun maillon une liste vide et la Figure 15.10 lajout du premier maillon une liste existante. La fonction malloc() permet dallouer la mmoire pour le premier lment. On ne rserve en effet que la mmoire ncessaire chaque cration dun lment supplmentaire. On aurait aussi bien pu faire appel la fonction calloc(). Attention dans ce cas aux diffrences dutilisation : calloc() initialisera le nouvel lment, pas malloc().
ntion Atte

Dans lexemple de code prcdent, nous avons omis de tester le retour de malloc(). Vous ne devez pas suivre cet exemple, il faut toujours contrler une allocation de mmoire. Quand on dclare un pointeur, il est bon de linitialiser NULL plutt que de laisser sa valeur indtermine.

ce Astu

http://fribok.blogspot.com/

Figure 15.9 Ajout dun lment dans une liste vide.

pointeur de tte
NULL

nouvelles donnes
NULL

Avant l'addition

pointeur de tte
new data NULL

Aprs l'addition

Figure 15.10 Ajout dans une liste dun nouveau premier lment.

pointeur de tte

donnes pointeur suivant nouvelles donnes NULL

donnes pointeur suivant

donnes NULL

Avant l'addition

pointeur de tte

donnes pointeur suivant nouvelles donnes pointeur suivant

donnes pointeur suivant

donnes NULL

Aprs l'addition

http://fribok.blogspot.com/

Ajout dun lment en queue de liste


partir du pointeur de tte, vous devez parcourir la liste pour retrouver le dernier lment. Suivez ensuite ces tapes : 1. Crez une structure en utilisant malloc() pour allouer la mmoire ncessaire. 2. Rednissez le pointeur du dernier lment pour quil pointe vers le nouvel lment (dont ladresse a t renvoye par malloc()). 3. Dnissez le pointeur du nouvel lment avec la valeur NULL qui indique la n de la liste. Voici le code correspondant :
person *current; ... current = head; while (current->next!= NULL) current = current->next; new = malloc(sizeof(struct person)); current->next = new; new->next = NULL;

pointeur de tte

donnes pointeur suivant

donnes pointeur suivant

donnes NULL

nouvelles donnes NULL

Avant laddition

pointeur de tte

donnes pointeur suivant

donnes pointeur suivant

donnes pointeur suivant

nouvelles donnes NULL

Aprs laddition

Figure 15.11 Ajout dun lment en queue de liste.

Ajout dun maillon au milieu


Lorsque lon travaille avec une liste chane, on doit la plupart du temps ajouter des maillons quelque part entre le premier et le dernier. Lemplacement dinsertion exact varie

http://fribok.blogspot.com/

en fonction de la gestion de la liste : elle peut tre trie, par exemple, sur un ou plusieurs lments de donnes. Vous devez donc dabord vous placer au bon endroit de la liste avant deffectuer lajout en suivant les tapes ci-aprs : 1. Localisez llment de la liste aprs lequel le nouveau maillon devra tre insr. Cet lment sera nomm lment de rfrence. 2. Crez une structure en utilisant malloc() pour allouer la mmoire ncessaire. 3. Modiez le pointeur de llment de rfrence pour quil pointe vers le nouvel lment (dont ladresse a t renvoye par malloc()). 4. Dnissez le pointeur du nouvel lment avec lancienne valeur de celui de llment de rfrence.
nouvelles donnes NULL

pointeur de tte

donnes pointeur suivant

donnes pointeur suivant

donnes NULL

Avant l'addition

pointeur de tte

nouvelles donnes pointeur suivant

donnes pointeur suivant

donnes pointeur suivant

donnes NULL

Aprs l'addition

Figure 15.12 Ajout dun lment au milieu dune liste chane.

Voici le code correspondant :


person *marker; /* Insrez ici le code ncessaire pour faire pointer llment de rfrence (marker) sur lemplacement requis de la liste.*/ ... new = malloc(sizeof(PERSON)); new->next = marker->next; marker->next = new;

http://fribok.blogspot.com/

Suppression dun lment de la liste


La suppression dun maillon se rsume un simple ajustement des pointeurs. Le processus varie en fonction de lemplacement de llment :

Pour supprimer le premier lment, il faut faire pointer le pointeur de tte vers le deuxime lment. Pour supprimer le dernier lment, il faut donner au pointeur de lavant dernier lment la valeur NULL. Pour supprimer un maillon intermdiaire, il faut modier le pointeur de llment qui le prcde pour le faire pointer vers llment qui suit llment supprimer.

Les lignes de code suivantes suppriment le premier lment de la liste chane :


head = head->next;

Les lignes de code suivantes suppriment le dernier lment de la liste chane :


person *current1, *current2; current1 = head; current2= current1->next; while (current2->next!= NULL) { current1 = current2; current2= current1->next; } current1->next = null; if (head == current1) head = null;

Enn, les lignes de code suivantes suppriment un lment intermdiaire de la liste chane :
person *current1, *current2; /* Insrer ici le code ncessaire pour que current1 pointe vers llment qui prcde le maillon supprimer. */ current2 = current1->next; current1->next = current2->next;

Aprs lexcution de ces lignes, llment supprim est toujours en mmoire, mais il ne fait plus partie de la liste puisquil nest plus "point". Dans vos programmes, noubliez pas de librer la mmoire occupe par cet lment avec la fonction free() (cette fonction est traite au Chapitre 20).

http://fribok.blogspot.com/

Un exemple de liste chane simple


Le Listing 15.12 illustre les oprations de base du traitement dune liste chane. Il na pas dautre objectif que celui de vous prsenter le code correspondant ces oprations puisquil ne reoit aucune donne de la part de lutilisateur et quil ne ralise aucune tche particulire : 1. Il dnit une structure et les pointeurs destins la liste. 2. Il insre le premier lment de la liste. 3. Il ajoute un lment en n de liste. 4. Il ajoute un lment en milieu de liste. 5. Il afche la liste obtenue lcran. Listing 15.12 : Les oprations de base dans une liste chane
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: /* Illustre les oprations de base */ /* dans une liste chane. */ #include <stdlib.h> #include <stdio.h> #include <string.h> /* Structure dun maillon. */ struct data { char name[20]; struct data *next; }; /* Dfinition des typedef de la structure */ /* et dun pointeur vers celle-ci. */ typedef struct data PERSON; typedef PERSON *LINK; int main() { /* Les pointeurs de tte (head), du nouvel lment (new), et de llment courant (current). */ LINK head = NULL; LINK new = NULL; LINK current = NULL; /* Ajout du premier lment. Il ne faut jamais supposer */ /* que la liste est vide au dpart, mme dans un */ /* programme de dmonstration comme celui-ci. */ new = malloc(sizeof(PERSON)); new->next = head; head = new; strcpy(new->name, "Abigail");

http://fribok.blogspot.com/

Listing 15.12 : Les oprations de base dans une liste chane (suite)
35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: } /* Ajout dun lment en fin de liste. */ /* Nous supposons que la liste contient au moins */ /* un lment. */ current = head; while (current->next!= NULL) { current = current->next; } new = malloc(sizeof(PERSON)); current->next = new; new->next = NULL; strcpy(new->name, "Catherine"); /* Ajoute un lment en seconde position dans la liste */ new = malloc(sizeof(PERSON)); new->next = head->next; head->next = new; strcpy(new->name, "Beatrice"); /* Affiche tous les maillons dans lordre. */ current = head; while (current!= NULL) { printf("%s\n", current->name); current = current->next; } exit(EXIT_FAILURE);

On obtient lafchage suivant :


Abigail Beatrice Catherine

Analyse La structure de donnes de la liste est dclare aux lignes 9 12. Les lignes 16 et 17 dnissent les typedef de la structure et dun pointeur vers cette structure. Le seul intrt de ces lignes est de simplier lcriture de struct data en PERSON et de struct data * en LINK. Les pointeurs qui permettront de manipuler la liste sont dclars et initialiss en NULL aux lignes 22 24.

http://fribok.blogspot.com/

Les lignes 30 33 ajoutent un nouveau lien en tte de liste, et la ligne 30 alloue une nouvelle structure de donnes. Attention, nous supposons ici que la rservation de mmoire avec malloc() sest droule avec succs. Vous devrez toujours contrler le retour de cette fonction dans vos programmes. La ligne 31 modie le pointeur next de cette nouvelle structure pour le faire pointer la mme adresse que le pointeur de tte. Nous ne nous sommes pas contents dattribuer la valeur nulle ce pointeur, car cette opration nest valable quavec une liste vide. Rdig de cette faon, ce code peut sappliquer une liste non vide. Le nouvel lment de tte va pointer sur llment qui tait prcdemment en tte, ce qui est bien le rsultat recherch. La ligne 32 fait pointer le pointeur de tte vers le nouvel enregistrement, et la ligne 33 y stocke quelques donnes. Lajout dun lment en queue de liste est un peu plus compliqu. Notre liste ne contient quun lment, mais nous ne pouvons pas considrer ce cas particulier pour un programme normal. Il faut donc parcourir la liste partir du premier lment jusquau dernier (la valeur du pointeur next est alors nulle). Cette opration est ralise aux lignes 38 42. Il suft ensuite dallouer une nouvelle structure, de faire pointer le dernier lment prcdent vers celle-ci et de donner la valeur nulle au pointeur next du nouvel lment (lignes 44 47). La tche suivante a permis dajouter un lment en milieu de liste : dans notre cas en deuxime position. Aprs lallocation dune nouvelle structure en ligne 50, le pointeur next du nouvel lment est dni pour pointer sur lancien deuxime lment qui sest transform en troisime lment (ligne 51), et le pointeur next du premier lment est dni pour pointer sur le nouvel lment (ligne 52). Le programme se termine en afchant tous les maillons de la chane. Il commence avec llment sur lequel pointe le pointeur de tte, puis il progresse dans la liste jusqu trouver le dernier lment reprsent par un pointeur NULL (lignes 56 61).

Implmentation dune liste chane


Maintenant que nous avons vu chaque cas particulier, nous allons vous prsenter, dans le programme du Listing 15.13, la ralisation dune liste chane pouvant contenir cinq caractres. Il est entendu que ces caractres auraient pu tre remplacs par nimporte quel autre type de donnes, le mcanisme tant le mme. Pour simplier, nous avons choisi un seul caractre. Ici, nous devons trier les maillons lors dun ajout. Cette opration supplmentaire qui donne au programme un caractre plus raliste que le programme prcdent. Chaque nouvel lment est ajout lendroit appropri selon lordre naturel des caractres.

http://fribok.blogspot.com/

Listing 15.13 : Cration dune liste chane de caractres


1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: /*========================================================* * Program: list1513.c * * Objectif: implmenter une liste chane * *=======================================================*/ #include <stdio.h> #include <stdlib.h> /* Structure dun maillon */ struct list { int ch; /*On utilise un int pour loger un caractre*/ struct list *next_rec; }; /* Les Typedef pour la structure et son pointeur. */ typedef struct list LIST; typedef LIST *LISTPTR; /* Prototypes des fonctions. */ LISTPTR add_to_list( int, LISTPTR ); void show_list(LISTPTR); void free_memory_list(LISTPTR); int main() { LISTPTR first = NULL; /* Pointeur de tte */ int i = 0; int ch; char trash[256]; /* Pour effacer le buffer de stdin.*/ while ( i++ < 5 ) /*Construire une liste de 5 lments*/ { ch = 0; printf("\nEntrez un caractre%d, ", i); do { printf("\nvaleurs entre a et z, svp: "); ch = getc(stdin); /* lire le caractre suivant*/ fgets(trash, sizeof(trash), stdin); /* nettoyer le buffer */ } while( (ch < a || ch > z) && (ch < A || ch > Z)); first = add_to_list( ch, first ); } show_list( first ); /* Afficher la liste en entier */

http://fribok.blogspot.com/

48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99:

free_memory_list( first );/*Restituer toute la mmoire*/ exit(EXIT_FAILURE); } /*========================================================* * Fonction: add_to_list() * But: Insrer un nouveau maillon dans la liste * Entre : int ch = caractre insrer * LISTPTR first = adresse du pointeur de tte * Retour: Adresse du pointeur de tte (first) *=======================================================*/ LISTPTR add_to_list( int ch, LISTPTR first ) { LISTPTR new_rec = NULL; /* adresse du nouvel lment*/ LISTPTR tmp_rec = NULL; /* temporaire */ LISTPTR prev_rec = NULL; /* Allocation mmoire. */ new_rec = malloc(sizeof(LIST)); if (!new_rec) /* Si plus de mmoire */ { printf("Mmoire insuffisante!\n"); exit(EXIT_FAILURE); } /* chaner les donnes */ new_rec->ch = ch; new_rec->next_rec = NULL; if (first == NULL) /*Ajout du premier maillon la liste*/ { first = new_rec; new_rec->next_rec = NULL; /* redondant, mais sr */ } else /* ce nest pas le premier lment */ { /* voir sil doit prcder le premier lment */ if ( new_rec->ch < first->ch) { new_rec->next_rec = first; first = new_rec; } else /* il faut lajouter au milieu ou la fin */ { tmp_rec = first->next_rec; prev_rec = first; /* voir o on doit linsrer. */ if ( tmp_rec == NULL ) {

http://fribok.blogspot.com/

Listing 15.13 : Cration dune liste chane de caractres (suite)


100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: /* ajout du second lment la fin */ prev_rec->next_rec = new_rec; } else { /* au milieu? */ while (( tmp_rec->next_rec!= NULL)) { if( new_rec->ch < tmp_rec->ch ) { new_rec->next_rec = tmp_rec; if (new_rec->next_rec!= prev_rec->next_rec) { printf("ERREUR"); getc(stdin); exit(0); } prev_rec->next_rec = new_rec; break; /* Le maillon a t ajout, */ } /* fin du while */ else { tmp_rec = tmp_rec->next_rec; prev_rec = prev_rec->next_rec; } } /* voir si ajout la fin */ if (tmp_rec->next_rec == NULL) { if (new_rec->ch < tmp_rec->ch ) { new_rec->next_rec = tmp_rec; prev_rec->next_rec = new_rec; } else /* la fin */ { tmp_rec->next_rec = new_rec; new_rec->next_rec = NULL; /*Redondant */ } } } } } return(first); } /*=======================================================* * Fonction: show_list * But: Affiche le contenu de la liste chane *=======================================================*/ void show_list( LISTPTR first ) { LISTPTR cur_ptr; int counter = 1;

http://fribok.blogspot.com/

156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186:

printf("\n\nAdr lm Position Val. Adr lm suivant\n"); printf("========== ======== ==== ================\n"); cur_ptr = first; while (cur_ptr!= NULL ) { printf(" %p ", cur_ptr ); printf("%2i %c", counter++, cur_ptr->ch); printf(" %p \n",cur_ptr->next_rec); cur_ptr = cur_ptr->next_rec; } } /*=======================================================* * Fonction: free_memory_list * But: libre la totalit de la mmoire acquise *=======================================================*/ void free_memory_list(LISTPTR first) { LISTPTR cur_ptr, next_rec; cur_ptr = first; /* Commencer au dbut */ while (cur_ptr!= NULL) /* jusqu la fin de la liste*/ { next_rec = cur_ptr->next_rec; /*adresse lment */ /* suivant */ free(cur_ptr); /* librer mmoire du maillon */ cur_ptr = next_rec; /* ajuster pointeur courant*/ } }

Lexcution de ce programme donne le rsultat suivant :


Entrez un caractre 1, Valeur entre a et z, svp: q Entrez un caractre 2, Valeur entre a et z, svp: b Entrez un caractre 3, Valeur entre a et z, svp: z Entrez un caractre 4, Valeur entre a et z, svp: c Entrez un caractre 5, Valeur entre a et z, svp: a Adr lm ========== 0x8451C3A 0x8451C22 0x8451C32 0x8451C1A 0x8451C2A Position ======== 1 2 3 4 5 Val. ==== a b c q z Adr lm suivant ================ 0x8451C22 0x8451C32 0x8451C1A 0x8451C2A 0

http://fribok.blogspot.com/

Analyse En analysant ce listing point par point, vous verrez quon y retrouve les diffrentes mthodes de mise jour dune liste que nous avons dtailles plus haut. La meilleure faon de bien comprendre ce listing est dexcuter le programme pas pas laide dun dbogueur. En surveillant lvolution des divers pointeurs de chanage, la mcanique de liaison devrait vous sembler plus claire.

ce Astu

Les dclarations initiales de dbut de programme devraient vous tre familires. Les lignes 10 18 dnissent la structure de la liste chane et les dnitions de type qui vont simplier lcriture du code. La fonction main() est simple, car elle fait appel des fonctions pour la mise jour de la liste chane. Lessentiel se trouve dans une boucle while lintrieur de laquelle se trouve une boucle do...while. Cette boucle intrieure sassure que lon a bien tap un caractre alphabtique, minuscule ou majuscule, non accentu. Lorsque le caractre est lu, on appelle la fonction add to list() laquelle on transmet le pointeur de tte de liste et les donnes ajouter. main() se termine, aprs avoir lu cinq caractres, par un appel show list() qui va afcher les caractres lus, dans lordre alphabtique, avec les pointeurs correspondants. La n de lafchage a lieu lorsque le pointeur vers llment suivant vaut NULL. La fonction la plus importante, ici, est add to list() (lignes 52 145). Cest aussi la plus complique. On dclare dabord (lignes 62 64) trois pointeurs qui seront utiliss pour pointer vers diffrents maillons. new rec va pointer sur la mmoire qui a t alloue pour le nouvel lment (ligne 67). new rec pointera vers le nouveau maillon qui doit tre ajout. tmp rec pointera vers le maillon courant de la liste en cours dvaluation. Sil y a plus dun maillon dans la liste, prev rec sera utilis pour pointer vers celui prcdemment valu. Remarquez quici, nous testons le rsultat de lappel malloc() et que, sil est infructueux, un message est afch, et le programme se termine (lignes 70 et 71). la ligne 75, on place le nouvel lment dans la structure pointe par new rec. Dans un programme rel, il y aurait gnralement plusieurs objets ranger ici. la ligne suivante, le pointeur vers llment suivant est mis NULL. la ligne 78, commence laddition du maillon en regardant sil y a dj des lments dans la liste. Si llment quon veut ajouter est le premier, on se contente de faire pointer le pointeur de tte, first, vers le nouvel lment (ligne 68). Si le nouveau maillon nest pas le premier, la fonction continue et on excute la branche else qui commence la ligne 83. La ligne 86 regarde si le nouveau maillon ne doit pas tre plac en tte de liste. Si cest le cas, les lignes 88 et 89 font le ncessaire.

http://fribok.blogspot.com/

Si les deux tests prcdents ont chou, on sait quil faut ajouter le nouveau maillon quelque part au milieu de la liste. Les lignes 93 et 94 ajustent les pointeurs tmp rec et prev rec dnis plus haut. Le premier pointe vers ladresse du second maillon de la liste, et prev rec prend la valeur du premier pointeur de la liste. Vous remarquerez que, sil ny a quun seul lment dans la liste, tmp rec vaut NULL. Ce cas particulier est test la ligne 98. Si cest le cas, on sait que le nouveau maillon sera le second, cest--dire la n de la liste. Pour cela, on se contente de faire pointer prev rec >next ptr vers le nouveau maillon et le tour est jou. Si tmp rec ne vaut pas NULL, on sait quil y a plus de deux maillons dans la liste. while, des lignes 106 125, va boucler sur le reste des maillons pour savoir quelle place on doit insrer le nouveau maillon. la ligne 108, on regarde sil est infrieur celui qui est actuellement point. Si cest le cas, on sait que cest l quil faut linsrer. Si le nouveau maillon est suprieur au maillon courant, il faut le comparer au suivant. Aux lignes 122 et 123, on incrmente tmp rec et next rec. Si le caractre insrer (cest--dire le nouveau maillon) est infrieur celui du maillon courant, on suit la logique prsente plus haut pour lajouter en milieu de liste : lignes 110 118. Une fois que cest fait, la boucle break permet de quitter while.
ntion Atte

Les lignes 111 116 contiennent du code de mise au point qui a t laiss dans le listing pour vous montrer comment tester ce genre de construction logicielle. Une fois que le programme tourne correctement, on doit normalement enlever ces instructions.

Lajout en n de liste a dj t trait plus haut. Il se traduit par une sortie normale de la boucle while (lignes 106 125). Linsertion seffectue au moyen des instructions prsentes aux lignes 128 140. Quand on atteint le dernier maillon, tmp rec >next rec doit tre gal NULL. Cest ce qui est test en ligne 128. la ligne 130, on regarde si le maillon doit tre insr avant ou aprs le dernier. Sil doit tre plac aprs, on fait pointer next rec sur le nouveau maillon et celui-ci sur NULL (ligne 138).

Dveloppements du programme du Listing 15.13


Les listes chanes ne sont pas aussi simple matriser. Lexemple que nous venons de voir montre quon peut, grce elles, construire des listes ordonnes. Au lieu dun seul caractre, on aurait pu traiter des chanes de caractres, des numros de tlphone ou nimporte quelle autre information. Ici, on avait choisi lordre croissant, mais on aurait pu adopter lordre dcroissant.

http://fribok.blogspot.com/

Suppression dans une liste chane


Pour tre complet, il faudrait aussi pouvoir raliser la suppression dun maillon de la liste. Lide gnrale est la mme, et il ne faut pas oublier de librer la mmoire correspondant aux maillons supprims. faire Essayer de bien comprendre la diffrence entre calloc() et malloc(). En particulier, souvenez-vous que calloc() initialise la mmoire alloue, ce que ne fait pas malloc(). ne pas faire Oublier de librer la mmoire correspondant aux maillons supprims.

eils Cons

Rsum
Dans ce chapitre, nous avons pass en revue plusieurs faons volues dutiliser des pointeurs. Vous savez, maintenant, que les pointeurs constituent lessence mme du C. Vous verrez, lusage, que rares sont les programmes C qui nen font pas usage. Vous avez vu comment utiliser des pointeurs pointant vers dautres pointeurs, et quoi peuvent servir des tableaux de pointeurs. Vous avez dcouvert comment C traite les tableaux plusieurs dimensions qui sont des tableaux de tableaux, et vous avez vu comment employer les pointeurs pour ces tableaux. Vous avez tudi lutilisation des pointeurs vers des fonctions. Finalement, vous avez appris implmenter les listes chanes, une mthode trs efcace denregistrement des donnes. Ce chapitre a t quelque peu ardu mais, bien que ces sujets soient un peu compliqus, leur intrt est certain. Vous touchez l quelques-unes des possibilits les plus sophistiques du C qui justient sa popularit actuelle.

Q&R
Q Quelle est la profondeur maximale quon peut utiliser avec des pointeurs pointant vers des pointeurs ? R Il ny a pas de limite thorique. Tout dpend dventuelles restrictions propres au compilateur que vous utilisez. Il est rare, cependant, davoir besoin de dpasser une profondeur de 3.

http://fribok.blogspot.com/

Q Y a-t-il une diffrence entre un pointeur vers une chane de caractres et un pointeur vers un tableau de caractres ? R Non. Cest la mme chose. Q Est-il ncessaire de mettre en pratique les concepts qui viennent dtre prsents dans ce chapitre pour tirer tous les avantages possibles du C ? R Pas vraiment. Mais vous ne proterez pas de tout ce qui fait la puissance de ce langage. Q Y a-t-il dautres circonstances dans lesquelles on peut tre amen utiliser des pointeurs vers des fonctions ? R Oui. Avec des menus, par exemple. Q Quels sont les deux avantages importants des listes chanes ? R Le premier est que la taille dune liste chane volue pendant lexcution du programme, vous navez pas besoin de la prvoir en crant le code. Le second est que ce genre de liste peut facilement tre trie, puisque lon ajoute ou que lon supprime des maillons nimporte o.

Atelier
Latelier vous propose quelques questions permettant de tester vos connaissances sur les sujets que nous venons daborder dans ce chapitre.

Quiz
1. crivez un processus qui dclare une variable x de type float, dclare et initialise un pointeur vers la variable, et dclare et initialise un pointeur vers ce pointeur. 2. Continuez lexemple ci-avant. Supposez que vous vouliez utiliser le pointeur vers un pointeur pour assigner la valeur 100 la variable x. Quy a-t-il ventuellement de faux dans linstruction suivante ?
*ppx = 100;

3. Supposons que vous ayez dclar un tableau de la faon suivante :


int tableau[2][3][4];

Quelle est la structure de ce tableau, vue par le compilateur C ? 4. Avec ce mme tableau, que signie lexpression tableau[0][0]?

http://fribok.blogspot.com/

5. Toujours avec ce mme tableau, quelles sont, parmi ces trois comparaisons, celles qui rpondent TRUE?
tableau[0][0] == &tableau[0][0][0] tableau[0][1] == tableau[0][0][1] tableau[0][1] == &tableau[0][1][0]

6. crivez le prototype dune fonction qui accepte un tableau de pointeurs de type char comme argument et ne renvoie rien. 7. Comment la fonction de la question 6 sait-elle combien dlments il y a dans le tableau de pointeurs qui lui a t pass ? 8. Quest-ce quun pointeur vers une fonction ? 9. crivez la dclaration dun pointeur vers une fonction qui renvoie un char et accepte un tableau de pointeurs vers un char comme argument. 10. Si vous aviez rpondu la question 9 par :
char *ptr(char *x[]);

quy aurait-il de faux ? 11. Lorsque vous dnissez la structure destine une liste chane, quel lment devezvous inclure ? 12. Que signie une valeur NULL pour un pointeur de tte ? 13. Comment sont relis les lments dune liste chane ? 14. Que font les dclarations suivantes ? a) int *var1;. b) int var2;. c) int **var3;. 15. Que font les dclarations suivantes ? a) int a[3][12];. b) int (*b)[12];. c) int *c[12];. 16. Que font les dclarations suivantes ? a) char *z[10];. b) char *y(int champ);. c) char (*x)(int champ);.

http://fribok.blogspot.com/

Exercices
1. crivez une dclaration pour un pointeur vers une fonction qui accepte un entier comme argument et renvoie une variable de type float. 2. crivez une dclaration pour un tableau de pointeurs vers des fonctions. Les fonctions accepteront toutes une chane de caractres comme argument et renverront un entier. quoi pourrait servir un tel tableau ? 3. crivez une dclaration convenant un tableau de dix pointeurs de type char. 4. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions suivantes ?
int x[3][12]; int *ptr[12]; ptr = x;

5. Crez une structure qui sera utilise avec une liste simplement chane. Elle devra recevoir les noms et adresses de vos connaissances. Comme plusieurs solutions sont possibles, nous ne donnons pas les rponses aux trois questions suivantes. 6. crivez un programme qui dclare un tableau de 12 x 12 caractres. Placez un X dans chaque lment et afchez le rsultat sous forme de grille en utilisant un pointeur vers le tableau. 7. crivez un programme qui range dix pointeurs vers des variables de type double. Le programme devra accepter dix nombres taps par lutilisateur, les trier et les afcher (consultez ventuellement le Listing 15.10).

http://fribok.blogspot.com/

16
Utilisation de chiers sur disque
Parmi les programmes que vous crivez, beaucoup utilisent des chiers sur disque pour diverses tches : sauvegarde de donnes ou dinformations de conguration, par exemple. Voici ce que vous allez tudier dans le prsent chapitre :

tablissement dun lien entre les ots et les chiers sur disque Deux types de chiers sur disque C Ouverture dun chier criture de donnes dans un chier Lecture de donnes partir dun chier Fermeture dun chier Gestion des chiers sur disque Utilisation de chiers temporaires

http://fribok.blogspot.com/

Flots et chiers sur disque


Comme vous lavez appris au Chapitre 14, C ralise ses entres/sorties au moyen de ots. Vous savez comment utiliser les ots prdnis du C, correspondant des priphriques spciques tels que le clavier, lcran. Les ots des chiers sur disque oprent de faon identique. Cest un des avantages des entres/sorties par ots. La principale nouveaut avec les ots des chiers sur disque est quici, cest votre programme qui doit explicitement crer le ot associ un chier sur disque particulier.

Types de chiers sur disque


Au Chapitre 14, vous avez vu quil existait deux sortes de ots : texte et binaire. Vous pouvez associer chaque type de ot un chier, et il est important de bien comprendre la distinction entre ces deux types pour les utiliser bon escient. Un ot de type texte est associ un chier en mode texte. Chaque ligne contient un nombre de caractres compris entre 0 et 255 (bornes comprises), et qui se termine par un ou plusieurs caractres signiant n de ligne. Une ligne nest pas une chane de caractres ; il ny a pas de \0 terminal. Lorsque vous utilisez un chier en mode texte, une traduction seffectue entre le caractre de n de ligne du C, \n, et les caractres utiliss par le systme dexploitation comme terminateur de ligne. Sur les systmes issus de DOS comme Windows, cest une association <retour chariot>, < la ligne>. Lorsquon crit des informations vers un chier sur disque, chaque \n est traduit par une combinaison <retour chariot>, < la ligne>. Inversement, la lecture, ces deux caractres sont traduits par un \n. Sur les systmes UNIX, il ny a aucune traduction, les caractres \n restent inchangs. Tout ce qui nest pas un chier texte est un ot de type binaire. Ces ots sont associs avec des chiers en mode binaire. Toutes les informations sont crites et lues telles quelles, sans aucune sparation entre les lignes et sans caractres de n de ligne. Les caractres \0 et \n nont plus de signication particulire. Certaines fonctions dentres/sorties sont limites un seul des deux types de chiers, alors que dautres peuvent utiliser les deux modes. Dans ce chapitre, nous allons tudier les fonctions associes aux deux modes.

Noms de chiers
Pour travailler avec des chiers sur disque, ceux-ci doivent avoir un nom. Les noms de chier sont exprims sous forme de chanes de caractres, comme nimporte quel texte. Les noms sont ceux quutilise le systme dexploitation ; ils doivent suivre les mmes rgles.

http://fribok.blogspot.com/

Les diffrents systmes dexploitation nappliquent pas forcment les mme rgles pour lautorisation des caractres dans les noms de chiers. Les caractres suivants, par exemple, sont interdits en Windows :
/ \: *? " < > |

Dans un programme C, un nom de chier peut aussi contenir des informations concernant le chemin daccs. Ce chemin reprsente lunit et/ou le rpertoire dans lequel se situe ce chier. Si votre nom de chier nindique pas le chemin daccs, on suppose que ce chier se situe lemplacement courant par dfaut du systme dexploitation. Lindication de ce chemin est cependant une bonne habitude prendre en programmation. Sur Windows, lantislash (\) spare les noms de rpertoire dans le chemin daccs. Par exemple, le nom
c:\data\liste.txt

se rfre un chier, appel liste.txt, situ dans le rpertoire \data du disque C. Vous nignorez pas que lantislash (\) prend un sens particulier en C, lorsquil apparat dans une chane de caractres. Pour reprsenter ce caractre lui-mme, on doit le redoubler. Ainsi, dans un programme C, une chane de caractres reprsentant un nom de chier complet scrit :
char *nomfich="c:\\data\\liste.txt";

Si vous tapez un nom de chier au clavier, vous ne tapez, bien entendu, quun seul antislash. Certains systmes dexploitation utilisent dautres sparateurs pour les noms de rpertoires. UNIX et Linux, par exemple, utilisent le slash normal (/).

Ouverture dun chier


Le processus permettant dtablir un lien entre un ot et un chier sur disque est appel louverture dun chier. Lorsque vous ouvrez un chier, il devient utilisable en lecture (les donnes peuvent tre entres dans le programme), en criture (le programme peut envoyer des rsultats dans le chier) ou dans les deux modes la fois. Lorsque vous avez ni dutiliser un chier, vous devez le refermer. Ce point sera abord plus loin, dans ce chapitre. Pour ouvrir un chier, utilisez la fonction de bibliothque fopen() est situ dans stdio.h, o il apparat ainsi :
FILE *fopen(const char *filename, const char *mode);

fopen(). Le prototype de

http://fribok.blogspot.com/

Ce prototype vous indique que fopen() renvoie un pointeur de type FILE qui est une structure dclare dans stdio.h. Les membres de cette structure sont utiliss par le programme pour diverses oprations daccs au chier, mais il est inutile de vous en proccuper. Ce que vous devez retenir, cest que, pour chaque chier que vous voulez ouvrir, vous devez dclarer un pointeur de type FILE. Lorsque vous appelez fopen(), cette fonction cre une instance de la structure FILE et renvoie un pointeur vers cette structure. Vous utiliserez ce pointeur dans les oprations ultrieures sur ce chier. Si la fonction fopen() choue, elle renvoie NULL. Elle peut chouer, par exemple, cause dune erreur matrielle ou dune tentative douverture dun chier inexistant. Largument filename est le nom du chier ouvrir. Comme nous lavons dit plus haut, il peut contenir le nom du disque et/ou le chemin daccs. Il peut tre reprsent par une chane de caractres constante, place entre guillemets, ou par un pointeur vers une chane de caractres situe nimporte o en mmoire. Largument mode spcie le mode dans lequel on doit ouvrir le chier. Dans ce contexte, mode commande le mode douverture du chier : texte ou binaire ; lecture ou criture ou les deux. Les valeurs possibles de mode sont donnes par le Tableau 16.1.
Tableau 16.1 : Valeurs de mode pour la fonction fopen()

Mode r w a r+

Signication
Ouverture du chier en lecture. Si le chier nexiste pas, fopen() renvoie NULL. Ouverture du chier en criture. Si le chier nexiste pas, il est cr. Sil existe dj, son contenu est effac. Ouverture du chier en mise jour (append). Si le chier nexiste pas, il est cr. Sil existe dj, les nouvelles informations sont ajoutes la n. Ouverture du chier en lecture et en criture. Si le chier nexiste pas, il est cr. Sil existe dj, les nouvelles informations sont crites en tte, crasant celles qui sy trouvaient prcdemment. Ouverture du chier en lecture et en criture. Si le chier nexiste pas, il est cr. Sil existe dj, son contenu est cras. Ouverture du chier en lecture et en mise jour. Si le chier nexiste pas, il est cr. Sil existe dj, les nouvelles informations sont ajoutes la n.

w+ a+

Le mode par dfaut est le mode texte. Pour ouvrir un chier en mode binaire, vous devez ajouter un b largument mode. Sur Linux, cela est facultatif car louverture dun chier est systmatiquement traite en mode binaire. Un argument mode contenant a oprera une ouverture pour mise jour en mode texte, alors que ab effectuera une ouverture pour mise jour en mode binaire.

http://fribok.blogspot.com/

Souvenez-vous que fopen() renvoie NULL si une erreur survient. Les conditions derreur qui peuvent provoquer ce type dincident sont :

utilisation dun nom de chier non valide ; tentative douverture dun chier dans un rpertoire ou un disque inexistants ; tentative douverture en mode lecture (r) dun chier inexistant.

Lorsque vous excutez fopen(), vous devez toujours tester lventualit dune erreur. Vous ne pouvez pas directement connatre le type de lerreur, mais vous pouvez envoyer un message lutilisateur et essayer douvrir nouveau le chier ou mettre n au programme. La plupart des compilateurs C proposent des fonctions non ANSI/ISO avec lesquelles vous pouvez obtenir des informations sur la nature de lerreur. Consultez la documentation de votre compilateur. Le Listing 16.1 vous prsente un programme de dmonstration de la fonction fopen(). Listing 16.1 : Utilisation de fopen() pour ouvrir un chier sur disque en diffrents modes
1:/* Dmonstration de la fonction fopen(). */ 2:#include <stdlib.h> 3:#include <stdio.h> 4: 5:int main() 6:{ 7:FILE *fp; 8:char filename[40], mode[4]; 9: 10:while (1) 11:{ 12: 13:/* Indiquer le nom de fichier et le mode. */ 14: 15:printf("\nTapez un nom de fichier: "); 16:lire_clavier(filename, sizeof(filename)); 17:printf("\nTapez un mode (3 caractres au plus): "); 18:lire_clavier(mode, sizeof(mode)); 19: 20:/* Essayer douvrir le fichier. */ 21: 22:if ((fp = fopen(filename, mode))!= NULL) 23:{ 24:printf("\nOuverture russie%s en mode%s.\n", 25:filename, mode); 26:fclose(fp); 27:puts("Tapez x pour terminer, \ ou nimporte quoi dautre pour continuer."); 28:if (getc(stdin) == x)

http://fribok.blogspot.com/

Listing 16.1 : Utilisation de fopen() pour ouvrir un chier sur disque en diffrents modes (suite)
29:break; 30:else 31:continue; 32:} 33:else 34:{fprintf(stderr, "\nErreur louverture du fichier\ 35:%s en mode%s.", filename, mode); 36:puts("Tapez x pour terminer, \ 37:ou nimporte quoi dautre pour ressayer."); 38:if (getc(stdin) == x) 39:break; 40:else 41:continue; 42:} 43:} 44: exit(EXIT_SUCCESS); 45:} Tapez un nom de fichier: list1601.c Tapez un mode (3 caractres au plus): w Ouverture russie 16p1.c en mode w. Tapez x pour terminer, ou nimporte quoi dautre pour continuer. j Tapez un nom de fichier: abcdef Tapez un mode (3 caractres au plus): r Erreur louverture du fichier abcdef en mode r. Tapez x pour terminer, ou nimporte quoi dautre pour ressayer. x

Analyse Le programme vous demande de lui indiquer un nom de chier et un mode de lecture. Ensuite, fopen() essaie douvrir le chier en rangeant dans fp le pointeur vers le chier (ligne 22). Linstruction if situe sur la mme ligne vrie que tout sest bien pass en comparant le pointeur renvoy NULL. Si fp ne vaut pas NULL, un message avertit lutilisateur que tout va bien et quil peut continuer. Dans le cas contraire, cest le bloc dinstructions plac aprs le else qui est excut : un message derreur est afch expliquant quil y a eu un problme. On propose ensuite lutilisateur de continuer ou de terminer le programme. Vous pouvez faire quelques essais avec divers noms de chiers et diffrents modes pour tudier le comportement de ce programme. La faon la plus simple de produire une erreur est de demander louverture en lecture dun chier qui nexiste pas (comme dans le cas du chier abcdef de notre exemple).

http://fribok.blogspot.com/

criture et lecture dun chier de donnes


Un programme utilisant un chier sur disque peut crire des donnes dans un chier, les lire ou faire les deux. Il y a trois faons dcrire dans un chier :

Vous pouvez utiliser des sorties formates pour sauvegarder des donnes mises en forme. Ce nest valable que pour des chiers texte. Les sorties formates sont principalement utilises lors de la cration de chiers contenant du texte et des valeurs numriques destins tre lus par dautres programmes tels que des tableurs ou des bases de donnes. Vous pouvez effectuer des sorties caractre par caractre pour crire des caractres isols ou des chanes de caractres dans un chier. Ce genre de pratique est maintenant rare car cela ralentit le programme de manire signicative avec les systmes dexploitations modernes (Windows, Linux, *BSD...). Vous pouvez utiliser des sorties directes pour sauvegarder le contenu dun bloc de mmoire directement vers un chier sur disque. Cette mthode nest valable que pour des chiers binaires. Lutilisation de ce type de sortie est le meilleur moyen de sauvegarder des valeurs destines tre rutilises plus tard par un programme C sur une machine de mme type.

Lorsque vous voulez lire des informations partir dun chier, vous avez le choix entre ces trois mmes options : entre formate, entre caractre par caractre ou entre directe. Le choix dpend presque entirement de la nature du chier lire. Vous choisirez la plupart du temps de lire des donnes dans le mode avec lequel elles auront t sauvegardes, mais rien ne vous y oblige. La lecture dun chier dans un mode diffrent de celui dans lequel il a t crit ncessite en effet une trs bonne connaissance du C et des formats de chier. La description que nous venons de faire suggre quil existe des tches bien appropries pour chacun de ces trois types. Mais ce nest pas une rgle absolue. Le langage C est assez souple (cest prcisment lun de ses avantages) pour quun programmeur adroit puisse utiliser nimporte quel type de chier pour nimporte quelle application. Mais, si vous tes un programmeur dbutant, ne cherchez pas vous compliquer la vie et suivez les conseils qui viennent dtre donns.

Entres et sorties formates


Les entres/sorties formates concernent le texte et les donnes numriques formats de faon particulire. On peut les comparer ce qui se passe avec le clavier et lcran lorsquon utilise les instructions scanf() et printf() dcrites au Chapitre 14. Nous allons commencer par les sorties formates.

http://fribok.blogspot.com/

Sorties formates vers un chier


Une sortie formate vers un chier se ralise en appelant la fonction de bibliothque fprintf(). Le prototype de fprintf() se trouve dans le chier den-tte stdio.h et se prsente ainsi :
int fprintf(FILE *fp, char *fmt,...);

Le premier argument est un pointeur vers un objet de type FILE. Pour crire des informations vers un chier sur disque particulier, il faut passer la fonction le pointeur rcupr au moment de louverture de ce chier par fopen(). Le second argument est une chane de caractres contenant le format utiliser. Vous avez dj rencontr ce type de chane de caractres, lorsque nous avons tudi printf() au Chapitre 14. Nous retrouvons ici exactement le mme type de chane. Pour plus de dtails, vous pouvez donc vous reporter au Chapitre 14. Largument nal est ... Quest-ce que cela signie ? Dans un prototype de fonction, des points de suspension (parfois appels ellipse) reprsentent un nombre variable darguments. Autrement dit, outre le pointeur de chier et la chane de caractres du format, fprintf() accepte zro, un ou plusieurs arguments supplmentaires, exactement comme printf(). Ces arguments sont les noms des variables crire dans le ot spci. Souvenez-vous que fprintf() fonctionne comme printf(), ce dtail prs que les sorties sont envoyes vers un chier sur disque, et non vers limprimante. Si vous indiquez comme ot de sortie stdout, les deux instructions se comporteront exactement de la mme faon. Le programme du Listing 16.2 utilise fprintf(). Listing 16.2 : Dmonstration de lquivalence entre les sorties faites avec fprintf() vers un chier sur disque et vers stdout
1:/* Dmonstration de la fonction fprintf(). */ 2:#include <stdlib.h> 3:#include <stdio.h> 4: 5:void clear_kb(void); 6: 7:int main() 8:{ 9:FILE *fp; 10:float data[5]; 11:int count; 12:char filename[20]; 13: 14:puts("Tapez 5 valeurs numriques en flottant."); 15:

http://fribok.blogspot.com/

16:for (count = 0; count < 5; count++) 17:scanf("%f", &data[count]); 18: 19:/* Demandez un nom de fichier et ouvrez le fichier. 20:Commencez par vider stdin de tout caractre qui 21:pourrait sy trouver. 22:*/ 23: 24:clear_kb(); 25: 26:puts("Indiquez un nom pour le fichier."); 27:lire_clavier(filename, sizeof(filename)); 28: 29:if ((fp = fopen(filename, "w")) == NULL) 30:{fprintf(stderr, "Erreur louverture du fichier %s.", 31:filename); 32:exit(EXIT_FAILURE); 33:} 34: 35:/* crivez les donnes numriques vers le fichier et stdout */ 36: 37:for (count = 0; count < 5; count++) 38:{ 39:fprintf(fp, "data[%d] =%f\n", count, data[count]); 40:fprintf(stdout, "data[%d] =%f\n", count, data[count]); 41:} 42:fclose(fp); 43: exit(EXIT_SUCCESS); 44:} 45: 46:void clear_kb(void) 47:/* Vide stdin de tout caractre en attente. */ 48:{ 49:char junk[80]; 50:fgets(junk, sizeof(junk), stdin); 51:} Tapez 5 valeurs numriques en flottant. 123.4 555.666 3.141592 0.00876 123456. Indiquez un nom pour le fichier. cocorico.txt data[0] data[1] data[2] data[3] data[4] = = = = = 123.400002 555.599976 3.141592 0.008760 123456.000000

http://fribok.blogspot.com/

Analyse Vous remarquerez quelques diffrences entre les valeurs que vous avez tapes et celles qui seront afches. Ce nest pas une erreur dans le programme, mais la consquence normale de la faon dont les nombres sont conservs dans la machine. Ce sont des erreurs de conversion entre la reprsentation externe des nombres et leur reprsentation interne. Le programme utilise fprintf() deux fois de suite : la premire fois vers le chier sur disque dont lutilisateur a donn le nom, la seconde vers stdout. La seule diffrence entre ces deux instructions est le premier argument. Une fois que vous aurez fait tourner le programme, utilisez un diteur de texte pour voir ce que contient le chier cocorico.txt (ou tout autre nom que vous aurez choisi). Ce chier devrait se trouver dans le mme rpertoire que les chiers du programme. Vous pourrez remarquer quil contient exactement ce qui a t afch sur lcran. Vous aurez not la prsence de la fonction clear kb() que nous avons tudie au Chapitre 14. Elle sert supprimer dventuels caractres subsistant aprs lappel scanf() , qui viendraient perturber la lecture du nom de chier. Il en rsulterait une erreur au moment de son ouverture.

Entres formates partir dun chier


Pour traiter une entre dinformations partir dun chier sur disque, on appelle la fonction de bibliothque fscanf() qui sutilise exactement comme scanf(), que nous avons tudie au Chapitre 14, un dtail prs : les informations proviennent cette fois, non plus du clavier (stdin), mais dun chier sur disque pralablement ouvert. Le prototype de fscanf() se trouve dans le chier den-tte stdio.h et se prsente ainsi :
int fscanf(FILE *fp, char *fmt,...);

Le premier argument est un pointeur vers un objet de type FILE. Pour lire des informations partir dun chier sur disque particulier, il faut passer la fonction le pointeur rcupr au moment de louverture de ce chier par fopen(). Le deuxime argument est une chane de caractres contenant le format utiliser. Vous avez dj rencontr ce type de chane de caractres, lorsque nous avons tudi scanf(), au Chapitre 14. Nous retrouvons ici exactement le mme type de chane. Le dernier argument, ..., signie quon trouve ensuite un nombre variable darguments. Ces derniers sont les adresses des variables dans lesquelles fscanf() placera les valeurs lues sur le chier disque. Pour plus de dtail, vous pouvez donc vous reporter au Chapitre 14. Pour essayer fscanf(), vous devez disposer dun chier texte contenant quelques nombres ou chanes de caractres dans un format acceptable par la fonction. laide dun

http://fribok.blogspot.com/

diteur de texte, crez un chier que vous appellerez, par exemple, infos.txt, dans lequel vous placerez cinq valeurs numriques exprimes en ottant et spares par des espaces ou des retours la ligne. Comme ceci :
123.4587.001 100.02 0.0004561.0005

Maintenant, compilez et lancez le programme du Listing 16.3. Listing 16.3 : Utilisation de fscanf() pour lire des donnes formates partir dun chier sur disque
1:/* Lecture de donnes formates sur un fichier avec fscanf(). */ 2:#include <stdlib.h> 3:#include <stdio.h> 4: 5:int main() 6:{ 7:float f1, f2, f3, f4, f5; 8:FILE *fp; 9: 10:if ((fp = fopen("infos.txt", "r")) == NULL) 11:{ 12:fprintf(stderr, "Erreur louverture du fichier.\n"); 13:exit(EXIT_FAILURE); 14:} 15: 16:fscanf(fp, "%f%f%f%f%f", &f1, &f2, &f3, &f4, &f5); 17:printf("Les valeurs sont:%f,%f,%f,%f, et%f.\n", 18:f1, f2, f3, f4, f5); 19: 20:fclose(fp); 21:exit(EXIT_SUCCESS); 22:} Les valeurs sont: 123.449997, 87.000999, 100.019997, 0.000456, et 1.000500.

Rappelons que, par dfaut, les valeurs afches avec une spcication %f ont six chiffres aprs le point dcimal (K & R, 2e dition, p. 154). Il en rsulte la mise en vidence, comme dans le programme prcdent, dapproximations de conversion. Analyse Le programme lit les cinq valeurs du chier que vous avez cr et les afche. la ligne 10, fopen() ouvre le chier en mode lecture et teste le rsultat. En cas derreur, un message derreur est afch et le programme se termine (lignes 12 et 13). La ligne 16 illustre

http://fribok.blogspot.com/

lutilisation de la fonction fscanf(). lexception du premier argument, elle est identique la fonction scanf() que nous avons dj utilise.

Entres et sorties par caractres


Pour des chiers sur disque, cela sapplique aussi bien des caractres isols qu des lignes de caractres. Souvenez-vous quune ligne est une suite dun nombre variable de caractres (ventuellement zro) termine par le caractre \n. Ce mode sutilise avec des chiers texte.

Entres par caractres


Il existe trois fonctions dentre de caractres : getc() et fgetc() pour les caractres isols et fgets() pour les suites de caractres. Les fonctions getc() et fgetc() Les fonctions getc() et fgetc() sont identiques et peuvent tre utilises lune la place de lautre. Elles acceptent un caractre isol prlev dans le ot spci. Le prototype de getc() se trouve dans stdio.h :
int getc(FILE *fp);

Largument fp est le pointeur renvoy par fopen() lors de louverture du chier. La fonction renvoie le caractre lu, ou EOF en cas derreur. getc() a t utilis dans des programmes prcdents pour lire un caractre partir du clavier. Nous avons ici un autre exemple de la souplesse des ots de C : la mme fonction est utilise pour lire partir du clavier ou dun chier. Si les fonctions getc() et fgetc() ne renvoient quun caractre, pourquoi leurs prototypes mentionnent-ils le retour dun type int? Lorsque vous lisez des chiers, vous devez tre capable de dtecter le caractre de n de chier qui est dclar en type int plutt que char sur certains systmes. Le programme du Listing 16.10 fait appel la fonction getc(). La fonction fgets() Cette fonction de bibliothque permet de lire une ligne de caractres partir dun chier sur disque. Son prototype se trouve dans stdio.h :
char *fgets(char *str, int n, FILE *fp);

http://fribok.blogspot.com/

Largument str est un pointeur vers une mmoire tampon dans lequel sera place la ligne de caractres lue ; n est le nombre maximum de caractres lire et fp est le pointeur de type FILE renvoy par fopen() lors de louverture du chier. fgets() lit des caractres dans le ot fp et les range en mmoire, depuis ladresse pointe par str jusqu la rencontre dun \n ou jusqu concurrence de n 1 caractres. En xant la longueur maximale de la chane lire, on vite tout risque dcrasement intempestif du contenu de la mmoire. Cest dailleurs pour cette raison que, pour le ot stdin, vous devez toujours utiliser fgets() et jamais gets(). Il reste un octet pour placer le \0 terminal que fgets() insre systmatiquement en n de chane. En cas de succs, fgets() renvoie str. Deux types derreurs peuvent se produire : Sil survient une erreur ou une n de chier sans quaucun caractre ne soit rang dans str, fgets() renvoie NULL, et la zone de mmoire pointe par str reste inchange. Sil survient une erreur ou une n de chier aprs quun ou plusieurs caractres aient t rangs dans str, fgets() renvoie NULL et la zone de mmoire pointe par str contient nimporte quoi. Vous voyez que fgets() ne lit pas ncessairement la totalit dune ligne (cest--dire jusquau \n nal). Il lui suft davoir lu n 1 caractres pour se terminer normalement. Lopration suivante portant sur ce mme chier se poursuivra lendroit prcis o la prcdente sest arrte. Pour tre sr davoir lu une ligne entire avec fgets(), il faut dimensionner le buffer de lecture une valeur sufsante, en accord avec la valeur donne n.

Sortie de caractres
Nous allons voir deux fonctions de sortie de caractres : putc() et fputs(). La fonction putc() La fonction putc() crit un unique caractre dans le ot spci. Son prototype se trouve dans stdio.h :
int putc(int ch, FILE *fp);

Largument ch reprsente le caractre crire. Comme dans les autres fonctions appliques des caractres, on lappelle de faon formelle un int, mais seul loctet de poids faible est utilis. Largument fp est le pointeur de type FILE renvoy lors de louverture du chier par fopen(). La fonction putc() renvoie le caractre quelle vient dcrire en cas de russite, ou EOF dans le cas contraire. La constante symbolique EOF est dnie dans stdio.h comme ayant la valeur 1. Aucun vritable caractre nayant cette valeur, il ny a pas de risque de confusion.

http://fribok.blogspot.com/

La fonction fputs() Pour crire une ligne de caractres dans un ot, on utilise la fonction de bibliothque fputs(). Cette fonction est semblable puts() que nous avons vue au Chapitre 14. La seule diffrence est que fputs() permet de spcier un ot de sortie alors que puts() travaille toujours avec stdout. La fonction fputs() ne rajoute pas de caractre \n la n de la chane. Son prototype se trouve dans stdio.h :
char fputs(char *str, FILE *fp);

Largument str est un pointeur vers la chane de caractres crire qui doit tre termine par un zro, et fp est le pointeur de type FILE renvoy par fopen() lors de louverture du chier. En cas de russite, fputs() renvoie une valeur non ngative. En cas derreur, elle renvoie EOF.

Entres sorties directes


Cette mthode dentres sorties ne concerne que les chiers en mode binaire. En sortie, la mmoire est crite telle quelle dans les blocs dinformations sur disque. En entre, la mmoire est garnie avec le contenu des blocs sur disque sans aucune conversion. Un seul appel de la fonction de sortie peut crire un tableau entier de valeurs de type double sur le disque, et il sufra dun seul appel de la fonction correspondante de lecture pour le rinstaller plus tard en mmoire. Les deux fonctions dentres-sorties directes sont fread() et fwrite().

La fonction fwrite()
La fonction de bibliothque fwrite() crit un bloc dinformations partir de la mmoire vers un chier ouvert en mode binaire. Son prototype se trouve dans stdio.h :
int fwrite(void *buf, int size, int count, FILE *fp);

Largument buf est un pointeur vers la rgion de la mmoire contenant les informations crire dans le chier. Ce pointeur est de type void, cest--dire quil peut pointer vers nimporte quoi. Largument size spcie la taille (en nombre doctets) des lments crire, et count, leur nombre. Ainsi, si vous voulez sauvegarder un tableau de 100 valeurs numriques de type entier, size vaudra 4 (taille dun int) et count vaudra 100. Vous pouvez utiliser loprateur sizeof() pour connatre la valeur de size. Largument fp est le pointeur de type FILE renvoy par fopen() lors de louverture du chier. En cas de russite, fwrite() renvoie le nombre darticles crits. En cas

http://fribok.blogspot.com/

derreur, elle renvoie une valeur infrieure. Pour voir si tout sest bien pass, on peut crire :
if(fwrite(buf, size, count, fp)!= count) fprintf(stderr, "Erreur dcriture sur disque.");

Voici quelques exemples dutilisation de fwrite(). Pour crire une seule variable x de type double dans un chier, on crira :
fwrite(&x, sizeof(x), 1, fp);

Pour crire un tableau data[] de 50 structures de type address sur disque, deux formes sont possibles :
fwrite(data, sizeof(address), 50, fp); fwrite(data, sizeof(data), 1, fp);

Dans le premier cas, on crit le tableau sous forme de 50 lments ayant chacun la taille dune structure address. Dans le second cas, on traite le tableau comme un lment unique. Le rsultat est le mme dans les deux cas.

La fonction fread()
La fonction de bibliothque fread() lit un bloc dinformations, partir dun chier ouvert en mode binaire, dans une zone de mmoire. Son prototype se trouve dans stdio.h :
int fread(void *buf, int size, int count, FILE *fp);

Largument buf est un pointeur vers la rgion de mmoire qui recevra les informations lues dans le chier. Comme pour fwrite(), il est de type void. Largument size spcie la taille (en nombre doctets) des lments lire et count, leur nombre, comme pour fwrite(). On peut utiliser loprateur sizeof() pour connatre la valeur de size. Largument fp est le pointeur de type FILE renvoy par fopen() lors de louverture du chier. En cas de russite, fread() renvoie le nombre darticles crits. En cas derreur (par exemple, sil ne reste plus assez de donnes lire), elle renvoie une valeur infrieure. Le programme du Listing 16.4 montre un exemple dutilisation de fwrite() et de fread().

http://fribok.blogspot.com/

Listing 16.4 : Utilisation de fwrite() et de fread() pour raliser des accs directs sur disque
1:/* Entres-sorties directes avec fwrite() et fread(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:#define SIZE 20 6: 7:int main() 8:{ 9:int count, array1[SIZE], array2[SIZE]; 10:FILE *fp; 11: 12:/* Initialiser array1[]. */ 13: 14:for (count = 0; count < SIZE; count++) 15:array1[count] = 2 * count; 16: 17:/* Ouvrir un fichier en mode binaire. */ 18: 19:if ((fp = fopen("direct.txt", "wb")) == NULL) 20:{ 21:fprintf(stderr, "Erreur louverture du fichier."); 22:exit(EXIT_FAILURE); 23:} 24:/* Sauvegarder array1[] dans le fichier. */ 25: 26:if (fwrite(array1, sizeof(*array1), SIZE, fp)!= SIZE) 27:{ 28:fprintf(stderr, "Erreur lcriture du fichier."); 29:exit(EXIT_FAILURE); 30:} 31: 32:fclose(fp); 33: 34:/* Ouvrir maintenant le mme fichier en mode binaire . */ 35: 36:if ((fp = fopen("direct.txt", "rb")) == NULL) 37:{ 38:fprintf(stderr, "Erreur louverture du fichier."); 39:exit(EXIT_FAILURE); 40:} 41: 42:/* Lire les informations dans array2[]. */ 43: 44:if (fread(array2, sizeof(*array2), SIZE, fp)!= SIZE) 45:{ 46:fprintf(stderr, "Erreur la lecture du fichier."); 47:exit(EXIT_FAILURE); 48:}

http://fribok.blogspot.com/

49: 50:fclose(fp); 51: 52:/* Afficher maintenant les deux tableaux pour montrer 53:que ce sont les mmes. */ 54:for (count = 0; count < SIZE; count++) 55:printf("%d\t%d\n", array1[count], array2[count]); 56: exit(EXIT_SUCCESS); 57:} 00 22 44 66 88 1010 1212 1414 1616 1818 2020 2222 2424 2626 2828 3030 3232 3434 3636 3838

Analyse Aprs avoir initialis un tableau aux lignes 14 et 15, le programme le sauvegarde sur disque la ligne 26 avec une instruction fwrite(). Puis il relit le contenu du chier dans un autre tableau la ligne 44 avec fread(). Les deux tableaux sont afchs aux lignes 54 et 55. Avec fwrite(), il ne peut pas arriver grand-chose en dehors dune erreur dcriture sur disque. En revanche, avec fread(), il faut bien savoir ce quon fait. La fonction na, en effet, aucun moyen de savoir quel type dinformations elle lit. Par exemple, un bloc de 100 octets pourrait tre constitu de 100 caractres, ou de 50 entiers, ou encore de 25 ottants. Il faut donc faire la lecture dans un tableau de mme type que les donnes contenues dans le chier sur disque. Si on se trompe, on nobtiendra aucune indication derreur, mais les donnes ainsi lues seront aberrantes. Dans cet exemple, vous noterez que chaque appel a une fonction dentres-sorties [fopen(), fwrite(), fread()] est suivi dun test derreur.

http://fribok.blogspot.com/

Entres-sorties tamponnes
Lorsquon a ni dutiliser un chier, il faut le refermer en appelant fclose(). Nous avons dj rencontr cette fonction dont le prototype se trouve dans stdio.h :
int fclose(FILE *fp);

Son argument fp est toujours le pointeur de type FILE renvoy lors de louverture initiale du chier. La fonction renvoie 0 si tout sest bien pass, ou EOF en cas derreur. Lors de cet appel, les tampons sont purgs, cest--dire que leur contenu est crit sur disque. Il est possible de refermer tous les chiers ouverts ( lexclusion de stdin, stdout et stderror) par un seul appel fcloseall(). Son prototype se trouve dans stdio.h :
int fcloseall(void)

La fonction renvoie le nombre de chiers quelle a ferms.


ntion Atte

fcloseall() est une extension GNU qui na rien de standard !

Lorsquun programme se termine, soit en atteignant la n du main(), soit par un appel exit(), tous les ots dentres-sorties sont automatiquement ferms. Cependant, il est prfrable de les refermer explicitement par un appel lune des deux fonctions que nous venons de voir cause de lutilisation de tampons pour tamponner les entres-sorties de ots. Lorsquon cre un ot li un chier sur disque, il y a automatiquement scration dune mmoire tampon associe ce ot. Un tampon est un bloc de mmoire utilis comme moyen de stockage temporaire pour les oprations dentres-sorties associes au ot. Les tampons sont ncessaires parce que les disques sont des priphriques de type bloc ; cela signie quon ne lit pas sur disque nimporte quel nombre doctets, mais un nombre constant correspondant la structure logique adopte sur le disque (celle-ci dpend ellemme du systme dexploitation). Le tampon associ au chier sert dinterface entre le disque (de type "bloc") et le ot (de type " caractre"). Lors dune criture, les informations sont accumules dans la mmoire tampon et ne seront crites que lorsque celle-ci sera pleine. Le mme processus est utilis, dans lautre sens, pour la lecture. Le langage C dispose de certaines fonctions permettant dagir sur la gestion des tampons, mais leur tude sortirait du cadre de ce livre. Il rsulte de ces considrations quon ne sait jamais quel moment auront lieu les vritables oprations de lecture ou dcriture sur disque. Si le programme se bloque, ou en cas de coupure de courant, on risque de perdre des informations.

http://fribok.blogspot.com/

Il est possible de purger (ushing) les tampons dun ot sans refermer celui-ci par un appel aux fonctions de bibliothque fflush(). Le prototype de cette fonction se trouve dans stdio.h :
int fflush(FILE *fp);

Largument fp est le pointeur renvoy par fopen() lors de louverture du chier. Si celuici tait ouvert en criture, le contenu du tampon est crit sur disque. Sil tait ouvert en lecture, le contenu du tampon est simplement purg. La fonction fflush() renvoie 0 si tout sest bien pass, ou EOF en cas derreur.
eils Cons

faire Ouvrir un chier avant dessayer de le lire ou dy crire. Utiliser sizeof() dans les appels de fread() et fwrite(). Refermer explicitement les chiers qui ont t ouverts. Ne pas faire Supposer implicitement correcte une opration sur un chier. Tester toujours le rsultat.

Accs squentiel oppos accs direct


Un indicateur de position est associ chaque chier ouvert. Il indique quel endroit du chier aura lieu les prochaines oprations de lecture et dcriture. La position est donne en nombre doctets partir du dbut du chier. Lorsquon cre un nouveau chier, lindicateur de position vaut 0 puisque le chier ne contient encore rien. Lorsquon ouvre un chier qui existe dj, lindicateur de position indique la n du chier si celui-ci est ouvert en mode "mise jour". Dans tout autre mode, il indique le dbut du chier. Les fonctions que nous venons dtudier exploitent et mettent jour cet indicateur. Lecture et criture seffectuent lendroit correspondant sa valeur. Ainsi, si vous ouvrez un chier en lecture et que vous lisez 10 octets, lindicateur de position prend la valeur 10 et cest l quaura lieu la lecture suivante. Pour lire squentiellement tout le chier, vous navez pas vous proccuper de son indicateur de position. Lorsque vous souhaitez exercer un contrle plus prcis sur la suite des oprations, utilisez les fonctions de la bibliothque standard du C qui permettent de manipuler cet indicateur. Vous pouvez, de cette faon, effectuer un accs alatoire votre chier, autrement dit, lire ou crire des blocs par-ci, par-l, sans que leurs positions soient ncessairement conscutives.

http://fribok.blogspot.com/

Les fonctions ftell() et rewind()


Pour manipuler lindicateur de position associ un chier, on utilise les fonctions de bibliothque ftell() et rewind() dont les prototypes se trouvent dans stdio.h :
void rewind(FILE *fp);

qui place lindicateur de position au dbut du chier et


long ftell(FILE *fp);

qui permet de connatre la valeur de lindicateur de position. Dans ces deux fonctions, largument fp est le pointeur renvoy par fopen() lors de louverture du chier. Lentier de type long renvoy par ftell() indique le nombre doctets sparant la position actuelle du dbut du chier. En cas derreur, la fonction renvoie 1L. Le programme du Listing 16.5 vous donne un exemple dutilisation de ces deux fonctions. Listing 16.5 : Utilisation de ftell() et rewind()
1:/* Dmonstration de ftell() et rewind(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:#define BUFLEN 6 6: 7:char msg[] = "abcdefghijklmnopqrstuvwxyz"; 8: 9:int main() 10:{ 11:FILE *fp; 12:char buf[BUFLEN]; 13: 14:if ((fp = fopen("texte.txt", "w")) == NULL) 15:{ 16:fprintf(stderr, "Erreur louverture du fichier."); 17:exit(EXIT_FAILURE); 18:} 19: 20:if (fputs(msg, fp) == EOF) 21:{ 22:fprintf(stderr, "Erreur lcriture du fichier."); 23:exit(EXIT_FAILURE); 24:} 25: 26:fclose(fp); 27: 28:/* Ouvrons maintenant le fichier en lecture. */ 29: 30:if ((fp = fopen("texte.txt", "r")) == NULL) 31:{

http://fribok.blogspot.com/

32:fprintf(stderr, "Erreur louverture du fichier."); 33:exit(EXIT_FAILURE); 34:} 35:printf("\nImmdiatement aprs louverture, position =%ld", 36:ftell(fp)); 37:/* Lire 5 caractres. */ 38: 39:fgets(buf, sizeof(buf), fp); 40:printf("\nAprs lecture de%s, position =%ld", buf, 41:ftell(fp)); 42:/* lire les 5 caractres suivants. */ 43: 44:fgets(buf, sizeof(buf), fp); 45:printf("\n\nLes 5 caractres suivant sont%s. \ 46:Position maintenant =%ld", buf, ftell(fp)); 47: 48:/* "Rembobiner" le flot. */ 49: 50:rewind(fp); 51: 52:printf("\n\nAprs rembobinage, la position est revenue \ 53:%Ld", ftell(fp)); 54: 55:/* Lire 5 caractres. */ 56: 57:fgets(buf, sizeoff(buf), fp); 58:printf("\net la lecture commence au dbut nouveau:%s\n", buf); 59:fclose(fp); 60:exit(EXIT_SUCCESS); 61:} Immdiatement aprs louverture, position = 0 Aprs lecture de abcde, position = 5 Les 5 caractres suivants sont fghij. Position maintenant = 10 Aprs rembobinage, la position est revenue 0 et la lecture commence au dbut nouveau: abcde

Analyse Ce programme crit la chane de caractres msg (les 26 lettres de lalphabet dans lordre) dans un chier appel texte.txt qui va tre ouvert aux lignes 14 18 en sortie. On sassure, bien entendu, que la cration sest bien passe. Les lignes 20 24 crivent msg dans le chier laide de la fonction fputs(), et vrient la russite de lopration. Le chier est referm la ligne 26, ce qui termine le processus de cration. Le chier est ensuite ouvert en lecture (lignes 30 34). La valeur retourne par ftell() est afche la ligne 35. La ligne 39 effectue une lecture de cinq caractres par fgets(). Ces cinq caractres ainsi que la nouvelle position du chier sont afchs la ligne 40. La fonction rewind() est appele la ligne 50 pour replacer le chier son dbut. On afche

http://fribok.blogspot.com/

nouveau sa position la ligne 52. Une nouvelle lecture (ligne 57) conrme la valeur laquelle on sattendait. Le chier est referm la ligne 59, avant la n du programme.

La fonction fseek()
On peut exercer un contrle plus prcis sur lindicateur de position dun ot en appelant la fonction de bibliothque fseek() qui permet de lui donner une nouvelle valeur. Le prototype de cette fonction se trouve dans stdio.h :
int fseek(FILE *fp, long offset, int origin);

(voir Tableau 16.2). Tableau 16.2 : Valeurs dorigine possible pour fseek().
Constante SEEK SET SEEK CUR SEEK END Valeur 0 1 2 Signication
Dbut du chier Position courante Fin du chier

Lappel fseek() renvoie 0 si lindicateur a rellement pris la valeur demande, ou une valeur non nulle dans le cas contraire. On voit, sur le Listing 16.6, comment utiliser la fonction fseek(). Listing 16.6 : Accs alatoire un chier laide de la fonction fseek()
1:/* Accs alatoire avec fseek(). */ 2: 3:#include <stdio.h> 4:#include <stdlib.h> 5: 6:#define MAX 50 7: 8:int main() 9:{ 10:FILE *fp; 11:int data, count, array[MAX]; 12:long offset; 13: 14:/* Initialiser le tableau. */ 15: 16:for (count = 0; count < MAX; count++) 17:array[count] = count * 10; 18: 19:/* Ouvrir un fichier binaire en criture. */

http://fribok.blogspot.com/

20: 21:if ((fp = fopen("random.dat", "wb")) == NULL) 22:{ 23:fprintf(stderr, "\nErreur louverture du fichier."); 24:exit(EXIT_FAILURE); 25:} 26: 27:/* crire le tableau dans le fichier puis le refermer . */ 28: 29:if ((fwrite(array, sizeof(*array), MAX, fp))!= MAX) 30:{ 31:fprintf(stderr, "\nErreur lcriture dans le fichier."); 32:exit(EXIT_FAILURE); 33:} 34: 35:fclose(fp); 36: 37:/* Ouvrir le fichier en lecture. */ 38: 39:if ((fp = fopen("random.dat", "rb")) == NULL) 40:{ 41:fprintf(stderr, "\nErreur louverture du fichier."); 42:exit(EXIT_FAILURE); 43:} 44: 45:/* Demander lutilisateur quel lment il veut lire. Lire 46:llment et lafficher. Arrter lorsquil rpond 1. */ 47: 48:while (1) 49:{ 50:printf("\nIndiquez llment lire, 0-%d, 1 pour \ 51:arrter: ", MAX1); 52:scanf("%ld", &offset); 53:if (offset < 0) 54:break; 55:else if (offset > MAX1) 56:continue; 57: 58:/* Dplacer lindicateur de position sur llment 59:spcifi. */ 60:if (fseek(fp, (offset*sizeof(int)), SEEK_SET)) 61:{ 62:fprintf(stderr, "\nErreur avec fseek()."); 63:exit(EXIT_FAILURE); 64:} 65: 66:/* Lire un unique entier. */ 67: 68:fread(&data, sizeof(data), 1, fp); 69: 70:printf("\nLlment %ld a la valeur%d.", offset, data); 71:} 72: 73:fclose(fp); 74:exit(EXIT_SUCCESS); 75:}

http://fribok.blogspot.com/

Indiquez llment lire, 0-49, 1 pour arrter: 5 Llment 5 a la valeur 50. Indiquez llment lire, 0-49, 1 pour arrter: 6 Llment 6 a la valeur 60. Indiquez llment lire, 0-49, 1 pour arrter: 49 Llment 49 a la valeur 490. Indiquez llment lire, 0-49, 1 pour arrter: 10 Llment 1 a la valeur 10. Indiquez llment lire, 0-49, 1 pour arrter: 0 Llment 0 a la valeur 0. Indiquez llment lire, 0-49, 1 pour arrter: 1

Analyse Le dbut du programme est identique celui du programme prcdent. Ici, le chier porte le nom de random.dat. Une fois quon a termin lcriture, on le referme (ligne 35) pour le rouvrir en lecture (ligne 39). En cas (improbable) derreur, un message est afch et le programme se termine immdiatement. Ensuite, dans une boucle while perptuelle (lignes 48 71), on demande lutilisateur dindiquer une valeur comprise entre 0 et 49 (lignes 50 et 52). Cette valeur est compare aux limites des enregistrements crits (0 49) par les instructions des lignes 53 56. Si elle est ngative, break permet de sortir de la boucle while. Si elle est suprieure MAX 1, on saute ce qui suit et on remonte en tte de la boucle while o on redemande une autre valeur. Lorsque la valeur est reconnue bonne, on place le chier lendroit demand (ligne 60), on lit lentier qui se trouve cet endroit (ligne 68), puis on lafche (ligne 70). Ensuite, la remonte normale dans la boucle while seffectue.

Dtection de la n d un chier
Lorsque vous connaissez exactement la longueur du chier que vous souhaitez lire, il nest pas ncessaire de pouvoir en dtecter la n. Par exemple, si vous avez sauvegard un tableau de cent entiers, vous savez que le chier a une longueur de 200 octets. Mais, dans certains cas, vous ignorez la longueur exacte du chier tout en voulant, quand mme, le lire du dbut jusqu la n. Il existe deux moyens de dtecter une n de chier. Lorsque vous lisez un chier crit en mode texte, caractre par caractre, vous pouvez tester son caractre de n. La constante symbolique EOF est dnie dans stdio.h comme

http://fribok.blogspot.com/

ayant une valeur gale 1, valeur ne correspondant aucun caractre rel. Ds lors, vous pouvez crire :
while ((c = fget(fp))!= EOF) { ... }

En mode binaire, cette mthode nest pas applicable puisquil ny a pas de valeur "rserve" et quon peut lire indiffremment toute association de bits. Il existe heureusement la fonction de bibliothque feof() (utilisable dans les deux modes, binaire et texte), qui est ainsi dnie :
int feof(FILE *fp);

Elle renvoie 0 lorsquon ne se trouve pas la n du chier, ou une valeur non nulle si on y est. ce moment, aucune autre opration de lecture nest possible, tout au moins, tant quun rewind() ou un fseek() na pas t effectu ou que le chier na pas t ferm puis rouvert. Le programme du Listing 16.7 montre comment utiliser feof(). Lorsque le programme vous demande un nom de chier, donnez-lui le nom dun chier texte (un de vos programmes C, par exemple). Assurez-vous que ce chier existe bien dans le rpertoire courant ou prcisez le chemin daccs avec le nom. Il va lire le chier dun bout lautre, en lafchant ligne par ligne, jusqu ce quil atteigne la n du chier. Listing 16.7 : Utilisation de la fonction feof() pour dtecter une n de chier
1:/* Dtection dune fin de fichier. */ 2: 3:#include <stdio.h> 4:#include <stdlib.h> 5: 6:#define BUFSIZE 100 7: 8:int main() 9:{ 10:int k; 11:char buf[BUFSIZE]; 12:char filename[60]; 13:FILE *fp; 14: 15:puts("Indiquez le nom du fichier texte afficher: "); 16:lire_clavier(filename, sizeof(filename)); 17: 18:/* Ouverture du fichier en lecture. */ 19:if ((fp = fopen(filename, "r")) == NULL) 20:{ 21:fprintf(stderr, "Erreur louverture du fichier."); 22:exit(EXIT_FAILURE);

http://fribok.blogspot.com/

Listing 16.7 : Utilisation de la fonction feof() pour dtecter une n de chier (suite)
23:} 24: 25:/* Lire une ligneet, si on nest pas la fin du fichier, 26:lafficher. */ 27: 28:do 29:{fgets(buf, sizeof(buf), fp); 30:if (!(k = feof(fp))) printf("%s", buf); 31:} while (k); 32: 33:fclose(fp); 34: exit(EXIT_SUCCESS); 35:}

Voici un exemple dexcution de ce programme :


Indiquez le nom du fichier texte afficher: hello.c #include <stdio.h> #include <stdlib.h> main() { printf("Bonjour le monde."); exit(EXIT_SUCCESS); }

Analyse On rencontre une boucle do while comme celle des lignes 28 31 dans les programmes effectuant un traitement squentiel. Il faut tester la n de chier immdiatement aprs la lecture et avant davoir imprim quoi que ce soit, car ce nest qu ce moment-l quon saura si on a rellement lu quelque chose. Si on est parvenu la n du chier, il faut donc viter dimprimer et, en n de boucle, ne pas remonter. La variable k, dans laquelle est mmoris le rsultat du test, va donc gouverner les deux instructions : lafchage et la remonte dans la boucle. Il faut noter que cette solution suppose implicitement quil ne se produit pas derreur sur la lecture du chier. Si ctait le cas, on ne sortirait pas de la boucle do while. Pour tester le programme, on constituera un chier quon appellera toto (par exemple, avec votre diteur de texte) dans lequel on placera simplement ces trois lignes :
abcd efgh ijkl

http://fribok.blogspot.com/

puis on lancera le programme. On verra alors safcher :


Indiquez le nom du fichier texte afficher: toto abcd efgh ijkl

eils Cons

faire Utiliser rewind() ou fseek() pour replacer le chier son dbut. Utiliser feof() pour tester la n du chier lorsquon travaille sur des chiers binaires. ne pas faire Utiliser EOF sur des chiers binaires (sur Linux, les chiers sont tous considrs comme binaires).

Fonctions de gestion de chier


Lexpression "gestion de chiers" concerne dautres oprations que la lecture et lcriture : leffacement, le changement de nom ou la recopie. La bibliothque standard du C contient des fonctions permettant deffacer un chier ou den changer le nom, et rien ne vous empche dcrire vous-mme des fonctions de recopie.

Effacement dun chier


Pour effacer un chier, il faut utiliser la fonction de bibliothque remove(). Elle est dnie dans stdio.h et voici son prototype :
int remove (const char *filename);

La variable filename est un pointeur vers une chane de caractres contenant le nom du chier effacer. Ce chier ne doit pas tre ouvert. Sil existe, il est effac, comme si vous aviez utilis la commande DEL (Windows) ou rm (Unix), do, dailleurs, cette instruction tire son nom), et la fonction renvoie 0. Si le chier nexiste pas ou possde un attribut read only (lecture seulement), si vous ne possdez pas les droits daccs requis, ou si une autre erreur survient, la fonction renvoie 1. Le court programme du Listing 16.8 montre comment utiliser remove(). vitez dutiliser, pour le tester, un chier auquel vous tenez !

http://fribok.blogspot.com/

Listing 16.8 : Utilisation de la fonction remove() pour effacer un chier sur disque
1:/* Dmonstration de la fonction remove(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int main() 6:{ 7:char filename[80]; 8: 9:printf("Indiquez le nom du fichier supprimer: "); 10:lire_clavier(filename, sizeof(filename)); 11: 12:if (remove(filename) == 0) 13:printf("Le fichier%s a t supprim.\n", filename); 14:else 15:fprintf(stderr, "Erreur la suppression du fichier \ 16:%s.\n", filename); 17: exit(EXIT_SUCCESS); 18:} Indiquez le nom du fichier supprimer: toto.bak Le fichier toto.bak a t supprim.

Analyse Le programme demande lutilisateur dindiquer le nom du chier effacer la ligne 9. Lappel remove() seffectue la ligne 12. Selon la valeur de retour, un message ou un autre est alors afch. La fonction unlink() existe galement. Cest dailleurs celle-ci que remove() fait appel.

Changement du nom dun chier


La fonction rename() permet de changer le nom dun chier. Son prototype est dans stdio.h :
int rename(const char *oldname, const char *newname);

Le chier dont le nom est point par oldname prend le nom point par newname. Pour tre certain dobtenir un rsultat correct avec tous les compilateurs, ces deux noms ne doivent comporter aucune indication dunit de disque ou de chemin daccs. Cette fonction admet quun chemin daccs diffrent soit indiqu pour chacun des noms, ce qui ralise en mme temps un dplacement du chier. Le compilateur Microsoft Visual C++ admet mme que lunit de disque soit diffrente pour chacun des deux chiers mais ce comportement nest pas standard. La fonction renvoie 0 si tout sest

http://fribok.blogspot.com/

bien pass, 1 dans le cas contraire. Le Listing 16.9 prsente un exemple de programme C utilisant cette fonction. Les causes derreur les plus frquentes sont :

Le chier oldname nexiste pas. Il existe dj un chier ayant le nom "newname". Vous avez indiqu un nom de disque ou un chemin daccs (dpend du compilateur utilis).

Listing 16.9 : Utilisation de la fonction rename() pour changer le nom dun chier sur disque
1:/* Utilisation de rename() pour changer le nom dun fichier. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int main() 6:{ 7:char oldname[80], newname[80]; 8: 9:printf("Indiquez le nom actuel du fichier: "); 10:lire_clavier(oldname, sizeof(oldname)); 11:printf("Indiquez le nouveau nom du fichier: "); 12:lire_clavier(newname, sizeof(newname)); 13: 14:if (rename(oldname, newname) == 0) 15:printf("%s sappelle maintenant%s.\n", oldname, newname); 16:else 17:fprintf(stderr, "Erreur survenue en changeant le nom \ 18:de%s.\n",oldname); 19: exit(EXIT_SUCCESS); 20:} Indiquez le nom actuel du fichier: toto.txt Indiquez le nouveau nom du fichier: titi.txt titi.txt sappelle maintenant titi.txt

Analyse Le Listing 16.9 illustre la puissance du langage C. Avec seulement 18 lignes de code, le programme remplace une commande du systme, et ce, de faon plus conviviale. la ligne 9, on demande lutilisateur de donner le nom du chier dont il veut changer le nom. la ligne 11, on lui demande le nouveau nom quil veut lui donner et, la ligne 14, on lui dit ce qui sest pass, selon la valeur renvoye par rename().

http://fribok.blogspot.com/

Copie dun chier


Il est souvent ncessaire de faire une copie dun chier : un double sous un nom diffrent (ou sous le mme nom, mais dans un autre rpertoire ou sur un autre support). En ligne de commande, on dispose de COPY (Windows) ou cp (Unix). En C, il nexiste pas de fonction de bibliothque pour cela ; aussi faut-il crire soi-mme un programme cette n. priori, cela pourrait vous paratre compliqu, mais il nen est rien. Voici la marche suivre : 1. Ouvrir le chier source en lecture et en mode binaire (ce qui permet de recopier nimporte quel type de chier). 2. Ouvrir le chier destinataire en criture et en mode binaire. 3. Lire quelques caractres dans le chier source. louverture, on est certain que le chier est plac son dbut, donc, inutile de faire appel fseek(). 4. Si un appel feof() indique quon a atteint la n du chier, fermer les deux chiers et terminer le programme. 5. Sinon, crire les caractres sur le chier destinataire et reprendre ltape 3. Le programme du Listing 16.10 contient une fonction, copy file(), laquelle on passe les noms du chier source et du chier destinataire, et qui effectue lopration de copie selon le schma que nous venons desquisser. Cette fonction nest pas appele en cas derreur louverture de lun des deux chiers. Une fois la copie termine, les deux chiers sont ferms et la fonction renvoie 0. Listing 16.10 : Fonction recopiant un chier
1:/* Copie dun fichier. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int file_copy(char *oldname, char *newname); 6: 7:int main() 8:{ 9:char source[80], destination[80]; 10: 11:/* Demander les noms des fichiers source et destination. */ 12: 13:printf("\nIndiquer le nom du fichier source: "); 14:lire_clavier(source, sizeof(source)); 15:printf("\nIndiquez le nom du fichier destination: "); 16:lire_clavier(destination, sizeof(destination)); 17: 18:if (file_copy(source, destination) == 0) 19:puts("Copie russie");

http://fribok.blogspot.com/

20:else 21:fprintf(stderr, "Erreur au cours de la copie"); 22: exit(EXIT_SUCCESS); 23: } 24:int file_copy(char *oldname, char *newname) 25:{ 26:FILE *fold, *fnew; 27:char buf[BUFSIZ]; 28:int n; 29:/* Ouverture du fichier source en lecture, mode binaire. */ 30: 31:if ((fold = fopen(oldname, "rb")) == NULL) 32:return 1; 33: 34:/* Ouverture du fichier destination en criture, 35:en mode binaire. */ 36:if ((fnew = fopen(newname, "wb")) == NULL) 37:{ 38:fclose (fold); 39:return 1; 40:} 41: 42:/* Lire le fichier source morceaux par morceaux. Si on na pas 43:atteint la fin du fichier, crire les donnes sur le 44:fichier destination. */ 45: 46:while (!feof(fold)) 47:{ 48:n = fread(buf, 1, sizeof(buf), fold); 49: 50:if (n > 0) 51:fwrite(buf, 1, n, fnew); 52:else 53:break; 54:} 55: 56:fclose (fnew); 57:fclose (fold); 58: 59:return 0; 60:} Indiquer le nom du fichier source: liste.doc Indiquer le nom du fichier destination: sauvegarde.txt Copie russie

Analyse La fonction copy file() permet de copier nimporte quoi, depuis un petit chier texte jusqu un norme chier de programme. Elle a, cependant, quelques limites. Si le chier

http://fribok.blogspot.com/

de destination existe dj, la fonction lefface sans demander la permission. Vous pourriez, titre dexercice, la modier pour tester lexistence du chier de destination et, dans ce cas, demander la permission de lcraser. Ici, main() est quasi identique au main() du Listing 16.9, lexception de la ligne 14. Ce nest pas rename() quon appelle, mais copy file(). Les instructions de cette fonction se trouvent aux lignes 24 60. Louverture du chier source se fait, en mode binaire, aux lignes 31 et 32 et celle du chier destinataire aux lignes 36 40. Si une erreur se produit ce moment, on referme le chier source. La boucle while des lignes 46 54 effectue la recopie du chier. La ligne 48 lit un bloc de caractres dans le chier source, fold. la ligne 50, on regarde si on a lu des donnes. Si oui, les donnes lues sont crites sur le chier de sortie, fnew. Sinon, on excute un break an de sortir de la boucle. On dtecte la n de chier avec feof() en tant que condition de while() ligne 46. Aux lignes 56 et 57, on trouve deux instructions fclose() qui referment les chiers. Remarque : On aurait pu effectuer la copie octet par octet. Cela est viter pour des raisons videntes de performances. Par ailleurs, la variable BUFSIZ est une variable dnie dans stdin.h.

Emploi de chiers temporaires


Certains programmes ont besoin dun ou plusieurs chiers de travail (temporaires) durant leur excution. Un chier temporaire est cr par le programme, utilis certaines ns pendant son excution et supprim juste avant que le programme se termine. Lorsque vous crez un chier temporaire, son nom importe peu puisquil ne sera pas conserv. Lessentiel est de ne pas utiliser un nom de chier existant dj. Pour cela, il existe dans la bibliothque standard C une fonction mkstemp() qui fabrique un nom de chier rput unique. Son prototype se trouve dans stdio.h :
int mkstemp(char *template);

Son argument est un pointeur vers un buffer contenant un modle de chier temporaire se terminant par "XXXXXX" (six fois la lettre X). Ce buffer est imprativement une chane de caractres cre avec la fonction malloc() (ou quivalent comme strdup() que nous allons utiliser ci-dessous). Vous penserez donc librer lespace mmoire ainsi rserv. La fonction mkstemp() a pour rle de crer un chier temporaire et de louvrir. Le nom du chier est crit en crasant les "XXXXXX" par des caractres de faon ce quil soit unique. Par ailleurs, mkstemp() renvoie un descripteur de chier (ou 1 en cas derreur) que vous pouvez transformer en descripteur de ux avec la fonction fdopen().

http://fribok.blogspot.com/

Le programme du Listing 16.11 montre comment utiliser cette mthode pour crer des noms de chier temporaires. Listing 16.11 : Utilisation de la fonction mkstemp() pour crer des noms de chier temporaires
1:/* Dmonstration de noms de fichier temporaires. */ 2: 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <string.h> 6: 7:int main() 8:{ 9:char *buffer; 10:int fd; 11:FILE *tmpfd 12: 13:/* Garnir le buffer avec un nom de fichier temporaire. */ 14: 15:buffer = strdup("fichier_XXXXXX"); 16: 17:/* Crer le fichier temporaire */ 18: 19:if((fd = mkstemp(buffer)) == -1) 20:{ 21:fprintf(stderr, "Impossible de crer le fichier\n"); 22:exit(EXIT_FAILURE); 23:} 24:if((tmpfd = fdopen(fd, "wb")) == NULL) 25:{ 26:fprintf(stderr, "Impossible de crer le flux\n"); 27:exit(EXIT_FAILURE); 28:} 29: 30:/* Utiliser le fichier temporaire */ 31:/* ... */32:/* Afficher les noms. */ 33: 34:printf("Nom de fichier temporaire:%s\n", buffer); 35: 36:/* Fermer le fichier et faire le mnage */ 37: 38:fclose(tmpfd); 39:free(buffer); 40: 41:exit(EXIT_SUCCESS); 42:} Nom de fichier temporaire: fichier_njcU7l

http://fribok.blogspot.com/

Analyse Les noms gnrs sur votre systme peuvent tre quelque peu diffrents de ceux que vous voyez ici. Remarque : il existe plusieurs fonctions pour crer des chiers temporaires ou des noms de chiers temporaires. Leur principe dutilisation les rend peu sres. Utilisez mkstemp() ou mieux, tmpfile(). Nous navons pas prsent cette dernire car elle ne permet pas de connatre le nom du chier temporaire ainsi cr. Si vous navez pas besoin de connatre le nom du chier temporaire que vous voulez utiliser, prfrez cette dernire dont le prototype est des plus simples :
FILE *tmpfile(void);

eils Cons

ne pas faire Supprimer un chier qui pourrait tre ncessaire plus tard. Essayer de changer le nom dun chier sur un autre disque. Oublier de supprimer les chiers temporaires crs.

Rsum
Dans ce chapitre, vous avez appris utiliser des chiers sur disque dans un programme C. Dans ce langage, les chiers sont considrs comme des ots, cest--dire comme une squence de caractres, de la mme faon que les ots prdtermins que vous avez dcouverts au Chapitre 14. On doit commencer par ouvrir un ot associ un chier sur disque avant de pouvoir lutiliser, et il faut le refermer aprs usage. Un ot sur disque peut tre ouvert en entre ou en sortie. Une fois le chier sur disque ouvert, vous pouvez lire les informations quil contient ou y crire dautres informations, ou les deux. Il existe trois types dentres-sorties : formates, caractres et directes. Le choix entre ces trois types dpend de lutilisation quon veut faire du chier. chaque chier sur disque se trouve associ un indicateur de position, qui indique le nombre doctets sparant la position actuelle du dbut du chier. Il prcise lendroit du chier o aura lieu la prochaine opration dentres-sorties. Certaines de ces oprations mettent jour lindicateur automatiquement. Pour les chiers en accs direct, la bibliothque standard du C propose des fonctions permettant de les manipuler. Il existe aussi des fonctions rudimentaires de gestion de chier qui permettent de supprimer un chier ou de changer son nom. Enn, nous avons vu comment crire un programme de recopie de chier.

http://fribok.blogspot.com/

Q&R
Q Puis-je spcier un disque et un chemin daccs avec le nom de chier dans les oprations remove(), rename(), fopen() et les autres fonctions de traitement de chier ? R Oui. Mais attention avec rename(): cette fonction sert galement dplacer un chier dun rpertoire dautre dun mme disque. Noubliez pas que lanti-slash est un caractre dchappement. Il faut donc le redoubler lintrieur dune chane de caractres. Avec UNIX, le sparateur de rpertoires est un slash ordinaire (/) et non un antislash (\). Q Peut-on lire des informations derrire une n de chier ? R Vous pouvez toujours essayer. Mais vos risques et prils ! Q Quarrive-t-il si je ne referme pas un chier ? R Refermer un chier aprs usage est une excellente habitude de programmation. En principe, le systme dexploitation referme les chiers qui sont encore ouverts lorsquun programme se termine. Mais mieux vaut ne pas trop compter l-dessus. Si le chier nest pas referm, avec certains systmes dexploitation (mais ni Unix, ni Linux ni Windows), vous pourriez ne plus pouvoir le rouvrir, car il serait considr comme tant toujours en cours dutilisation. Q Combien de chiers puis-je ouvrir en mme temps ? R Cest une question laquelle on ne peut pas rpondre simplement. Cela dpend essentiellement de certains paramtres du systme dexploitation. Q Puis-je lire un chier squentiel avec des fonctions prvues pour laccs direct ? R Lorsquon lit un chier en squence, il nest pas ncessaire dutiliser des fonctions comme fseek(), car lindicateur de position suit dlement le droulement des oprations successives. Mais ce nest pas dfendu ; cest seulement inutile.

Atelier
Latelier vous propose quelques questions permettant de tester vos connaissances sur les sujets que nous venons daborder dans ce chapitre.

Quiz
1. Quelle est la diffrence entre un ot en mode texte et un ot en mode binaire ? 2. Que doit faire votre programme avant de pouvoir accder un chier sur disque ?

http://fribok.blogspot.com/

3. Lorsque vous ouvrez un chier avec fopen(), quelles informations devez-vous spcier et que renvoie la fonction ? 4. Quelles sont les trois mthodes gnrales daccs un chier ? 5. Quelles sont les deux mthodes gnrales pour lire les informations contenues dans un chier ? 6. Que vaut EOF? 7. quel moment utilise-t-on EOF? 8. Comment dtecte-t-on la n dun chier en mode texte et en mode binaire ? 9. Quest-ce que lindicateur de position de chier et comment peut-on modier sa valeur ? 10. Lorsquon ouvre un chier, o pointe lindicateur de position ? (Si vous ntes pas sr de votre rponse, voyez le Listing 16.5.)

Exercices
1. Indiquez deux faons de restaurer la valeur de lindicateur de position au dbut dun chier. 2. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions qui suivent ?
FILE *fp; int c; if ((fp=fopen(oldname, "rb")) == NULL) return 1; while ((c = fgetc(fp))!= EOF) fprintf(stdout, "%c", c); fclose (fp);

Pour les exercices 4 8 qui suivent, il y a plusieurs solutions possibles. Nous nen donnerons pas le corrig. 4. crivez un programme qui afche le contenu dun chier sur lcran. 5. crivez un programme qui ouvre un chier et compte le nombre de caractres quil contient. Une fois le chier entirement lu, ce nombre sera afch. Contrlez la solution avec lutilitaire wc (wc fichier) sur Linux 6. crivez un programme qui ouvre un chier texte existant et le recopie vers un nouveau chier texte, en transformant toutes les lettres minuscules en majuscules et en laissant les autres caractres inchangs.

http://fribok.blogspot.com/

7. crivez un programme qui ouvre nimporte quel chier sur disque, le lit par blocs de 128 octets et afche le contenu de chaque bloc sur lcran, la fois en hexadcimal et sous forme de caractres ASCII. 8. crivez une fonction qui ouvre un chier temporaire dans un mode spci. Tous les chiers temporaires crs par cette fonction devront tre automatiquement referms et supprims avant que le programme ne se termine. (Astuce : utilisez la fonction de bibliothque atexit().)

http://fribok.blogspot.com/

Exemple pratique 5

Comptage des caractres


Le programme prsent dans cette nouvelle section pratique, count ch, ouvre le chier texte spci, et compte le nombre doccurrences de chaque caractre rencontr. Tous les caractres standards du clavier sont pris en compte comme les majuscules et minuscules, les chiffres, les espaces, et les marques de ponctuation. Les rsultats apparaissent lcran. Ce programme illustre quelques techniques de programmation intressantes et fournit une application utile. Vous pourrez rcuprer les rsultats dans un chier laide de loprateur de redirection (>) :
count_ch > results.txt

Cette commande va excuter le programme et enregistrer ses donnes en sortie dans le chier results.txt plutt que les afcher lcran. Il sufra ensuite dditer le chier ou de limprimer. Listing Exemple pratique 5 : compte_chaine.c : pour compter les caractres dun chier
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: /* Compte le nombre doccurrences de chaque caractre dans un fichier. */ #include <stdio.h> #include <stdlib.h> int file_exists(char *filename); int main() { char ch, source[80]; int index; long count[127];

http://fribok.blogspot.com/

11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63:

FILE *fp; /* Lecture des noms de fichiers source et destination. */ fprintf(stderr, "\nEntrez le nom du fichier source: "); lire_clavier(source,sizeof(source)); /* Contrle de lexistance du fichier source. */ if (!file_exists(source)) { fprintf(stderr, "\n%s nexiste pas.\n", source); exit(EXIT_FAILURE); } /* Ouverture du fichier. */ if ((fp = fopen(source, "rb")) == NULL) { fprintf(stderr, "\nErreur douverture%s.\n", source); exit(EXIT_FAILURE); } /* Initialisation des lments du tableau. */ for (index = 31; index < 127; index++) count[index] = 0; while { ch /* if ( 1 )

= fgetc(fp); Fin si fin de fichier */ (feof(fp)) break; /* Ne compte que les caractres entre 32 et 126. */ if (ch > 31 && ch < 127) count[ch]++;

} /* Affichage des rsultats. */ printf("\nChar\t\tCount\n"); for (index = 32; index < 127; index++) printf("[%c]\t%d\n", index, count[index]); /* Fermeture du fichier et sortie. */ fclose(fp); return(EXIT_SUCCESS); } int file_exists(char *filename) { /* Renvoie TRUE si le fichier existe, sinon FALSE. */ FILE *fp; if ((fp = fopen(filename, "r")) == NULL) return 0; else { fclose(fp); return 1; } }

http://fribok.blogspot.com/

Analyse Vous pourrez utiliser la fonction file exists() des lignes 51 63 dans dautres programmes quoique la fonction stat() sufse amplement cette tche. Elle sassure de lexistence du chier dont elle reoit le nom en argument en tentant de louvrir en mode lecture (ligne 56). Elle renvoie TRUE si le chier existe et FALSE dans le cas contraire. Notez lutilisation de la fonction fprintf() pour afcher les messages lcran plutt que printf() comme en ligne 14, par exemple. printf() envoie en effet toujours ses donnes en sortie vers stdout et lutilisateur ne voie apparatre aucun message si loprateur de redirection renvoie ces donnes dans un chier. Lutilisation de fprintf() impose lenvoie des messages vers stderr, dont le contenu est toujours afch lcran. Pour terminer cette analyse, observez la faon dont on a utilis la valeur numrique de chaque caractre comme index dans le tableau des rsultats (lignes 40 et 41). Llment count[32], par exemple, stocke le nombre despaces rencontrs parce que la valeur numrique 32 reprsente ce caractre.

http://fribok.blogspot.com/

17
Manipulation de chanes de caractres
Le texte, sous forme de chanes de caractres, constitue une partie importante de beaucoup de programmes. Jusquici, vous avez appris faire des entres-sorties de texte, et vous savez comment les chanes de caractres sont conserves en mmoire. Pour leur manipulation, C dispose dune grande varit de fonctions. Dans ce chapitre, nous allons tudier :

La longueur dune chane La copie et la concatnation de chanes Les fonctions de comparaison de chanes Les recherches dans une chane de caractres La conversion dune chane de caractres Comment tester des caractres lintrieur dune chane

http://fribok.blogspot.com/

Longueur dune chane


Vous savez que, dans un programme C, une chane est une suite de caractres dont le dbut est repr par un pointeur et la n par un zro binaire (le caractre NULL, cod \0). On a souvent besoin de connatre la longueur dune chane, cest--dire le nombre de caractres se trouvant entre le premier caractre et le zro terminal. On utilise pour cela la fonction de bibliothque standard strlen(), dont le prototype se trouve dans string.h :
size_t strlen(char *str);

Sans doute vous posez-vous des questions au sujet de ce curieux type : size t. Il est dni dans string.h comme tant un unsigned. La fonction strlen() renvoie donc un entier non sign. Ce type est utilis pour la plupart des fonctions traitant des caractres. Souvenez-vous quil quivaut unsigned. Largument pass strlen() est un pointeur vers la chane de caractres dont vous voulez connatre la longueur. Vous rcuprez le nombre de caractres rels, cest--dire terminateur (\0) non compris. Le programme du Listing 17.1 montre un exemple dutilisation de strlen(). Listing 17.1 : Utilisation de la fonction strlen() pour connatre la longueur dune chane de caractres
1:/* Utilisation de la fonction strlen(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:int main() 7:{ 8:size_t length; 9:char buf[80]; 10: 11:while (1) 12:{ puts("\nTapez une lignede texte (une lignevierge \ 13:pour terminer)."); 14: lire_clavier(buf, sizeof(buf)); 15: 16: length = strlen(buf); 17: 18: if (length!= 0) 19: printf("\nLa longueur de cette ligneest de%u \ 20:caractres.", length); 21: else 22: break; 23:} 24: exit(EXIT_SUCCESS); 25:}

http://fribok.blogspot.com/

Tapez une ligne de texte (une ligne vierge pour terminer). Portez ce vieux whisky au juge blond qui fume. La longueur de cette ligne est de 46 caractres. Tapez une ligne de texte (une ligne vierge pour terminer).

Analyse Aux lignes 13 et 14, on afche un message et on lit une chane de caractres dans buf. la ligne 16, on appelle strlen() qui permet de rcuprer la longueur de la chane dans la variable length. Il ne reste plus alors qu lafcher, ce quon fait la ligne 19.

Copie de chanes de caractres


Il existe trois fonctions pour copier des chanes de caractres. tant donn la faon dont elles sont traites par C, on ne peut pas simplement faire une copie en assignant le contenu dune variable une autre, comme cela se pratique dans dautres langages. On doit explicitement copier les caractres constitutifs de la premire chane dans les emplacements mmoire affects la seconde. Les fonctions de recopie sont : strcpy(), strncpy() et strdup(). Si vous connaissez la taille de la zone recopier, vous pouvez galement utiliser memcpy() qui est priori encore plus performante. Lorsquon appelle des fonctions de traitement de chanes de caractres dans un programme, il ne faut pas oublier dinclure le chier den-tte string.h.

La fonction strcpy()
La fonction de bibliothque strcpy() copie une chane entire dans une zone de mmoire. Son prototype est :
char *strcpy(char *destination, char *source);

Le caractre terminal \0 est, lui aussi, recopi. La fonction renvoie un pointeur vers la nouvelle chane, destination. Avant dutiliser strcpy(), il faut allouer assez de place pour la chane destinataire, car strcpy() recopie systmatiquement la totalit de la chane source. Le Listing 17.2 illustre lutilisation de strcpy(). Lorsquun programme utilise malloc() pour allouer de la mmoire, il est bon de librer la mmoire acquise avant de terminer le programme en appelant la fonction free(). Nous tudierons cette dernire fonction au Chapitre 20.

Info

http://fribok.blogspot.com/

Listing 17.2 : Avant dappeler strcpy(), vous devez allouer assez de mmoire pour la chane destinataire
1:/* Dmonstration de strcpy(). */ 2: 3:#include <stdlib.h> 4:#include <stdio.h> 5:#include <string.h> 6: 7:char source[] = "Une chane de caractres."; 8: 9:int main() 10:{ 11:char dest1[80]; 12:char *dest2; 13: 14:printf("\nsource:%s", source); 15: 16:/* Copier vers dest1 est correct parce que dest1 pointe 17:vers une zone de 80 octets. */ 18: 19:strcpy(dest1, source); 20:printf("\ndest1:%s", dest1); 21: 22:/* Pour copier vers dest2 vous devez allouer de la place.*/ 23: 24:dest2 = malloc(strlen(source) +1); 25:strcpy(dest2, source); 26:printf("\ndest2:%s\n", dest2); 27: 28:/* Faire une copie dans une zone non alloue est 29:suicidaire.Linstruction suivante pourraitcauser 30:de srieux problmes: 31:strcpy(dest3, source); */ 32:exit(EXIT_SUCCESS); 33:} source: Une chane de caractres. dest1:Une chane de caractres. dest2:Une chane de caractres.

Analyse Il ny a pas grand-chose dire de ce programme. Linclusion de stdlib.h est ncessaire, car on y trouve le prototype de malloc(). On remarquera cependant lallocation dynamique de mmoire la ligne 24, dont la longueur est dtermine par la longueur de la chane recopier. Attention ne pas "dcommenter" les instructions des lignes 28 33 !

http://fribok.blogspot.com/

La fonction strncpy()
Cette fonction est similaire strcpy(), ce dtail prs quun troisime argument permet de xer lavance la longueur de la chane source recopier. Son prototype est le suivant :
char *strncpy(char *destination, char *source, size_t n);

Les arguments destination et source sont des pointeurs vers les chanes de destination et dorigine. La fonction copie, au plus, les n premiers caractres de la chane source. Si strlen(source) est infrieur n, les positions suivantes seront garnies par des valeurs NULL, concurrence dun total de n caractres recopis. Si strlen(source) est suprieur n, aucun terminateur ne se trouvera plac dans la chane destination. Le programme du Listing 17.3 montre lutilisation de strncpy(). Listing 17.3 : Utilisation de la fonction strncpy()
1:/* Utilisation de la fonction strncpy(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:char dest[] = ".........................."; 7:char source[] = "abcdefghijklmnopqrstuvwxyz"; 8: 9:int main() 10:{ 11:size_t n; 12: 13:while (1) 14:{ 15:puts("Indiquez le nombre de caractres copier (1-26)"); 16:scanf("%d", &n); 17: 18:if (n > 0 && n < 27) 19:break; 20:} 21: 22:printf("\nAvant strncpy destination =%s", dest); 23: 24:strncpy(dest, source, n); 25: 26:printf("\nAprs strncpy destination =%s\n", dest); 27: exit(EXIT_SUCCESS); 28:} Indiquez le nombre de caractres copier (1-26) 17 Avant strncpy destination = .......................... Aprs strncpy destination = abcdefghijklmnopq.........

http://fribok.blogspot.com/

Analyse Aux lignes 13 20, on trouve une boucle while demandant lutilisateur de taper un nombre compris entre 1 et 26. On ne sort de la boucle que lorsque la valeur tape est correcte. Notez quil aurait t plus lgant dcrire :
size_t n=0; do {puts("Indiquez le nombre de caractres copier (1-26)"); scanf("%d", &n); } while (n < 1 || n > 26);

ntion Atte

Il ne faut pas que le nombre de caractres copis excde lemplacement allou cet effet.

La fonction strdup()
Cette fonction est identique strcpy(), sauf quelle effectue sa propre allocation de mmoire pour la chane destinataire par un appel implicite malloc(). Son prototype est le suivant :
char *strdup(char *source);

Largument source est un pointeur vers la chane de caractres recopier. La fonction renvoie un pointeur vers la chane contenant la copie, ou NULL si la mmoire ncessaire nest pas disponible. Le Listing 17.4 montre un exemple dutilisation de strdup(). Si cette fonction nest pas une fonction ANSI elle est nanmoins conforme des standards tels que POSIX et BSD 4.3, ce qui est un gage de protabilit. Listing 17.4 : Utilisation de la fonction strdup() pour copier une chane avec allocation automatique de mmoire
1:/* La fonction strdup(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:char source[] = "Cest la chane source."; 7: 8:int main() 9:{ 10:char *dest; 11: 12:if ((dest = strdup(source)) == NULL)

http://fribok.blogspot.com/

13:{ 14:fprintf(stderr, "Erreur dallocation mmoire."); 15:exit(EXIT_FAILURE); 16:} 17: 18:printf("Destination =%s\n", dest); 19:exit(EXIT_SUCCESS); 20: } Destination = Cest la chane source.

La fonction memcpy()
Cette fonction est similaire strncpy() au niveau de son prototype. Elle sen distingue par le fait quelle copie exactement le nombre doctets indiqus dans le troisime argument, sans tenir compte dun ventuel caractre nul de n de chane. Son prototype est le suivant :
void *memcpy(char *destination, char *source, size_t n);

Les arguments destination et source sont des pointeurs vers les chanes de destination et dorigine. La fonction copie exactement les n premiers caractres de la chane source. Le grand intrt par rapport strcpy() et strncpy() est sa rapidit car elle na pas tester en interne la prsence dun caractre nul. Cette fonction sert principalement lorsque vous connaissez dj la longueur de la chane destination, ce qui est dailleurs le cas aprs avoir rserv lespace mmoire ncessaire la recopie. Le programme du Listing 17.5 montre lutilisation de memcpy(). Listing 17.5 : Utilisation de la fonction memcpy()
1:/* Utilisation de la fonction memcpy(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:char source[] = "abcdefghijklmnopqrstuvwxyz"; 7: 8:int main() 9:{ 10:char *dest 11:size_t n; 12: 13:n = strlen(source) + 1; 14:dest = malloc(n * sizeof(*dest)); 15:if(dest == NULL)

http://fribok.blogspot.com/

Listing 17.5 : Utilisation de la fonction memcpy() (suite)


16:{ 17:fprintf(stderr, "Erreur dallocation mmoire."); 18:exit(EXIT_FAILURE); 19:} 20: 21:memcpy(dest, source, n); 22: 23:printf("\nAprs memcpy destination =%s\n", dest); 24:exit(EXIT_SUCCESS); 25:} Aprs memcpy destination = abcdefghijklmnopqrstuvwxyz

Analyse Nous avons besoin de la taille de lespace mmoire rserver, taille qui est calcule ligne 13. La mmoire est rserve ds la ligne suivante. Lorsquil sagit de recopier la chane source, il est la fois inutile de recalculer la longueur de la chane (puisque nous la connaissons depuis la ligne 13) et inutile dutiliser une fonction comme strcpy() qui va perdre du temps rechercher le caractre nul de n de chane. Cest donc memcpy() la fonction la plus adapte ici. Remarquez au passage que les lignes 11 21 auraient pu tre remplaces par un simple dest = strdup(source).

Concatnation de chanes de caractres


Peut-tre ce terme ne vous dit-il rien ? Concatner deux objets, cest les mettre bout bout (lorsque cest possible, bien sr, ce qui est le cas pour les chanes de caractres). La bibliothque standard du C contient deux fonctions cet usage : strcat() et strncat(). Toutes deux ncessitent linclusion du chier string.h.

La fonction strcat()
Son prototype est :
char *strcat(char *str1, char *str2);

Cette fonction concatne les chanes str1 et str2, cest--dire quelle ajoute une copie de str2 la suite de str1. Le programme du Listing 17.6 donne un exemple dutilisation de strcat().

http://fribok.blogspot.com/

Listing 17.6 : Utilisation de la fonction strcat() pour concatner deux chanes de caractres
1:/* La fonction strcat(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:char str1[27] = "a"; 7:char str2[2]; 8: 9:int main() 10:{ 11:int n; 12: 13:/* On met un caractre NULL lextrmit de str2[]. */ 14: 15:str2[1] = \0; 16: 17:for (n = 98; n < 123; n++) 18:{ 19:str2[0] = n; 20:strcat(str1, str2); 21:puts(str1); 22:} 23:exit(EXIT_SUCCESS); 24:} ab abc abcd abcde abcdef abcdefg abcdefgh abcdefghi abcdefghij abcdefghijk abcdefghijkl abcdefghijklm abcdefghijklmn abcdefghijklmno abcdefghijklmnop abcdefghijklmnopq abcdefghijklmnopqr abcdefghijklmnopqrs abcdefghijklmnopqrst abcdefghijklmnopqrstu abcdefghijklmnopqrstuv abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvwx abcdefghijklmnopqrstuvwxy abcdefghijklmnopqrstuvwxyz

http://fribok.blogspot.com/

Analyse Les codes ASCII des lettres b z sont 98 122. Ce programme utilise ces codes ASCII pour donner une illustration de lemploi de strcat(). La boucle for des lignes 17 22 assigne ces valeurs lune aprs lautre str2[0]. Comme str2[1] contient dj le terminateur (ligne 15), il en rsulte un garnissage progressif illustr par la sortie cran de la ligne 21.

La fonction strncat()
Cette fonction de bibliothque effectue une concatnation que vous pouvez limiter puisque le troisime argument en prcise la porte. Le prototype est :
char *strncat(char *str1, char *str2, size_t n);

Si str2 contient plus de n caractres, ses n premiers caractres sont ajouts lextrmit de str1. Si str2 contient moins de n caractres, toute la chane est ajoute lextrmit de str1. Dans les deux cas, un terminateur est plac la n de str1. Vous devez allouer assez de place str1 pour la runion des deux chanes. Le programme du Listing 17.7 illustre lutilisation de cette fonction. Listing 17.7 : Utilisation de la fonction strncat() pour concatner deux chanes de caractres
1:/* La fonction strncat(). */ 2: 3:#include <stdio.h> 4:#include <string.h> 5: 6:char str2[] = "abcdefghijklmnopqrstuvwxyz"; 7: 8:int main() 9:{ 10:char str1[27]; 11:int n; 12: 13:for (n=1; n < 27; n++) 14:{ 15:strcpy(str1, ""); 16:strncat(str1, str2, n); 17:puts(str1); 18:} 18:exit(EXIT_SUCCESS) 19:}

http://fribok.blogspot.com/

a ab abc abcd abcde abcdef abcdefg abcdefgh abcdefghi abcdefghij abcdefghijk abcdefghijkl abcdefghijklm abcdefghijklmn abcdefghijklmno abcdefghijklmnop abcdefghijklmnopq abcdefghijklmnopqr abcdefghijklmnopqrs abcdefghijklmnopqrst abcdefghijklmnopqrstu abcdefghijklmnopqrstuv abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvwx abcdefghijklmnopqrstuvwxy abcdefghijklmnopqrstuvwxyz

Analyse Vous vous interrogez peut-tre au sujet de linstruction qui gure sur la ligne 15 : strcpy(str1, "");. Elle recopie une chane vide, cest--dire ne contenant que le seul terminateur (\0). Il en rsulte que le premier caractre de str1, str1[0], est NULL. On aurait pu faire la mme chose en crivant : str1[0] = 0; ou str1[0] = \0;. Nous vous rappelons par ailleurs que si vous connaissez la longueur des deux chanes de caractres, il est plus efcace dutiliser memcpy(). Les trois lignes suivantes effectuent la mme chose :
strcat(str1, str2); strncat(str1, str2, n2); memcpy(str1+n1, str2, n2+1);

n1 et n2 sont les longueurs des chanes de caractres telles que renvoyes par la fonction strlen() (et non pas la taille de lespace mmoire qui inclut lui le caractre nul de n de chane).

http://fribok.blogspot.com/

Comparaison de deux chanes de caractres


Lorsquon compare deux chanes de caractres, cest, le plus souvent, pour savoir si elles sont diffrentes. Si elles sont ingales, lune delles est "infrieure" lautre. Cette "infriorit" est dtermine par la valeur des codes ASCII qui, par bonheur, respectent lordre alphabtique. les lettres majuscules (codes ASCII de 65 90) ont assez bizarrement des valeurs infrieures leurs quivalents minuscules (codes ASCII de 97 122). La chane "ZEBRA" va donc tre value comme infrieure la chane "apple" par ces fonctions C. La bibliothque C ANSI contient deux types de fonctions de comparaison : entre deux chanes entires et entre deux chanes sur une longueur prdtermine.

Comparaison de deux chanes entires : la fonction strcmp()


La fonction strcmp() compare deux chanes de caractres, caractre par caractre. Son prototype se trouve dans string.h :
int strcmp(char *str1, *str2);

Les arguments str1 et str2 pointent sur les deux chanes comparer. La fonction renvoie les valeurs indiques par le Tableau 17.1, et le programme du Listing 17.8 donne un exemple dutilisation.
Tableau 17.1 : Valeurs renvoyes par strcmp()

Valeur de retour < 0 = 0 > 0

Signication str1 < str2 str1 = str2 str1 > str2

Listing 17.8 : Utilisation de strcmp() pour comparer deux chanes de caractres


1:/* La fonction strcmp(). */ 2: 3:#include <stdio.h> 4:#include <string.h> 5: 6:int main() 7:{ 8:char str1[80], str2[80];

http://fribok.blogspot.com/

9:int x; 10: 11:while (1) 12:{ 13:/* Lecture au clavier de deux chanes de caractres. */ 14: 15:printf("\n\nTapez la premire chane (Entre pour \ 16:terminer): "); 17:lire_clavier(str1, sizeof(str1)); 18: 19:if (strlen(str1) == 0) 20:break; 21: 22:printf("\nTapez la seconde chane: "); 23:lire_clavier(str2, sizeof(str2)); 24: 25:/* Comparaison des deux chanes et affichage du rsultat.*/ 26: 27:x = strcmp(str1, str2); 28: 29:printf("\nstrcmp(%s,%s) renvoie%d", str1, str2, x); 30:} 31:exit(EXIT_SUCCESS); 32:} Tapez la premire chane (Entre pour terminer): Premire chane Tapez la seconde chane: Seconde chane strcmp(Premire chane,Seconde chane) renvoie 1 Tapez la premire chane (Entre pour terminer): abcdefgh Tapez la seconde chane: abcdefgh strcmp(abcdefgh,abcdefgh) renvoie 0 Tapez la premire chane (Entre pour terminer): zoologue Tapez la seconde chane: abricot strcmp(zoologue,abricot) renvoie 1 Tapez la premire chane (Entre pour terminer):

Analyse Lutilisateur est invit taper ses deux chanes de caractres (lignes 15, 17, 22 et 23), le rsultat est afch par le printf() de la ligne 19. Faites quelques essais avec ce programme, en tapant deux fois la mme chane, une fois en minuscules, lautre en majuscules, par exemple.

http://fribok.blogspot.com/

Comparaison partielle de deux chanes de caractres : la fonction strncmp()


La fonction de bibliothque strncmp() compare un nombre donn de caractres pris dans deux chanes de caractres. Voici son prototype :
int strncmp(char *str1, *str2, size_t n);

Les arguments str1 et str2 pointent sur les deux chanes comparer et n indique le nombre de caractres comparer. La fonction renvoie les valeurs indiques par le Tableau 17.1 ; le programme du Listing 17.9 donne un exemple dutilisation. Listing 17.9 : Comparaison partielle de deux chanes de caractres
1:/*La fonction strncmp(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:char str1[] = "Voici la premire chane."; 7:char str2[] = "Voici la seconde chane."; 8: 9:int main() 10:{ 11:size_t n, x; 12: 13:puts(str1); 14:puts(str2); 15: 16:while (1) 17:{ 18:puts("\n\nTapez le nombre de caractres comparer, \ 19:0 pour terminer."); 20:scanf("%d", &n); 21:if (n <= 0) 22:break; 23: 24:x = strncmp(str1, str2, n); 25: 26:printf("\nComparaison de%d caractres. strncmp() \ 27:renvoie%d.", n, x); 28:} 29:exit(EXIT_SUCCESS); 30:} Voici la premire chane. Voici la seconde chane. Tapez le nombre de caractres comparer, 0 pour terminer. 9 Comparaison de 9 caractres. strncmp() renvoie 0. Tapez le nombre de caractres comparer, 0 pour terminer.

http://fribok.blogspot.com/

12 Comparaison de 12 caractres. strncmp() renvoie 1. Tapez le nombre de caractres comparer, 0 pour terminer. 0

Analyse Le programme compare les deux chanes respectivement dnies aux lignes 6 et 7. Les lignes 13 et 14 afchent les chanes sur lcran an que lutilisateur puissent facilement se reprer. La boucle while des lignes 16 28 autorise plusieurs essais. On en sort lorsque lutilisateur tape 0 (lignes 21 et 22). Le rsultat est afch la ligne 26.

Comparaison de deux chanes en ignorant leur casse


La bibliothque C ANSI ne fournit malheureusement aucune fonction de comparaison de chanes qui ne tienne pas compte de la casse. Cependant, vous trouverez les fonctions strcasecmp() et strncasecmp() sur les systmes dexploitations qui respectent la norme POSIX (comme Windows et Linux). Certains compilateurs C proposent galement leurs propres fonctions "maison" pour cette opration. Symantec utilise la fonction strcmpl(), Microsoft fait appel la fonction stricmp() et Borland propose strcmpi() et stricmp(). Consultez le manuel de rfrence de votre bibliothque pour connatre la fonction spcique de votre compilateur. Lorsque vous utilisez ce type de fonction, les deux chanes Smith et SMITH apparaissent identiques. Modiez la ligne 27 du Listing 17.8 avec la fonction de comparaison approprie (qui ignore la casse) en fonction de votre compilateur et testez ce programme de nouveau.

Recherche dans une chane de caractres


La bibliothque C contient six fonctions effectuant des recherches dans une chane de caractres. Toutes demandent linclusion de string.h.

La fonction strchr()
La fonction strchr() recherche la premire occurrence dun caractre particulier. Son prototype est :
char *strchr(char *str, int ch);

La recherche seffectue de la gauche vers la droite, cest--dire dans lordre croissant des positions. Elle sarrte ds quune galit est trouve ou que lon parvient au bout de la chane. En cas de russite, la fonction renvoie un pointeur vers le caractre cherch. Elle renvoie NULL en cas dchec.

http://fribok.blogspot.com/

Pour obtenir la position du caractre trouv (lorsque cest le cas), il suft de faire la diffrence entre la valeur renvoye et ladresse du dbut de la chane. Le programme du Listing 17.10 montre comment on peut oprer. Souvenez-vous que le premier caractre dune chane occupe la position 0. Comme beaucoup dautres fonctions de C qui sappliquent aux chanes, strchr() diffrencie les majuscules des minuscules. Elle indiquera, par exemple, que le caractre F est absent de la chane raffle. Listing 17.10 : Utilisation de strchr() pour rechercher la position dun caractre dans une chane
1:/* Recherche de la position dun caractre dans une chane 2:avec strchr(). */ 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <string.h> 6:int main() 7:{ 8:char *loc, buf[80]; 9:int ch; 10: 11:/* Taper la chane de caractres et le caractre. */ 12: 13:printf("Tapez la chane de caractres: "); 14:lire_clavier(buf, sizeof(buf)); 15:printf("Tapez le caractre chercher: "); 16:ch = getchar(); 17: 18:/* effectuer la recherche. */ 19: 20:loc = strchr(buf, ch); 21: 22:if (loc == NULL) 23:printf("On na pas trouv le caractre%c.", ch); 24:else 25:printf("Le caractre%c a t trouv la position \ 26:%d.", ch, loc-buf); 27:exit(EXIT_SUCCESS); 28:} Tapez la chane de caractres: Il tait un petit navire Tapez le caractre chercher: p Le caractre p a t trouv la position 12.

Analyse Cest lappel strchr() de la ligne 20 qui effectue la recherche. Le test de la ligne 22 permet de choisir entre les deux messages afcher, selon le rsultat de la recherche. En cas de russite, la position du caractre trouv est dtermine par la soustraction effectue la ligne 26.

http://fribok.blogspot.com/

La fonction strrchr()
strrchr() est analogue strchr(), cet important dtail prs : au lieu de rechercher la premire occurrence dun caractre spci dans une chane, elle recherche sa dernire occurrence. Son prototype est :
chr *strrchr(char *str, int ch);

Cette fonction renvoie un pointeur vers la dernire occurrence du caractre spci, ou NULL si ce caractre ne gure pas dans la chane. Pour tester son fonctionnement, il suft de modier la ligne 20 dans le Listing 17.10 en remplaant strchr() par strrchr().

La fonction strcspn()
La fonction de bibliothque strcspn() recherche la premire occurrence dans une chane, de lun des caractres dune seconde chane. Son prototype est le suivant :
char *strcspn(char *str1, char *str2);

La fonction commence par sattaquer au premier caractre de str1 en cherchant sil est gal lun des caractres de str2. Si ce nest pas le cas, elle passe au deuxime caractre de str2 et ainsi de suite. Il est important de se souvenir que la fonction ne recherche pas la chane str2, mais seulement les caractres quelle contient. Lorsquelle trouve une galit, elle renvoie un pointeur vers lemplacement du caractre trouv dans str1. En cas dchec, elle renvoie strlen(str1), indiquant ainsi que la correspondance nexiste quavec le terminateur de str1. Le programme du Listing 17.11 montre un exemple dutilisation de strcspn(). Listing 17.11 : Recherche dun caractre parmi plusieurs dans une chane de caractres avec strcspn()
1:/* Recherche avec strcspn(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:int main() 7:{ 8:charbuf1[80], buf2[80]; 9:size_t loc; 10: 11:/* Entre des chanes de caractres. */ 12:printf("Tapez la chane de caractres dans laquelle on \ 13: cherchera:\n"); 14:lire_clavier(buf1, sizeof(buf1)); 15:printf("Tapez la chane de caractres contenant les \ 16: caractres chercher:\n"); 17:lire_clavier(buf2, sizeof(buf2));

http://fribok.blogspot.com/

Listing 17.11 : Recherche dun caractre parmi plusieurs dans une chane de caractres avec strcspn() (suite)
18: 19:/* Effectuer la recherche. */ 20:loc = strcspn(buf1, buf2); 21: 22:if (loc ==strlen(buf1)) 23:printf("On na trouv aucune correspondance."); 24:else 25:printf("La premire correspondance a t trouve \ 26: la position%d.\n", loc); 27:exit(EXIT_SUCCESS); 28:} Tapez la chane de caractres dans laquelle on cherchera: le chat de la voisine Tapez la chane de caractres contenant les caractres chercher: bord La premire correspondance a t trouve la position 8.

Analyse Le programme ressemble celui du Listing 17.10, mais au lieu de rechercher loccurrence dun seul caractre, on recherche, cette fois, les possibilits doccurrence dun des caractres dune chane. Ici, le premier caractre commun aux deux chanes est le d de "de" qui correspond au d de "bord". On remarquera le test qui permet (ligne 22) dafcher quaucune correspondance na t trouve. Il est diffrent du test habituel. La simplicit du programme nappelle gure dautres commentaires.

La fonction strspn()
Cette fonction sapparente la prcdente, comme nous allons le voir dans le paragraphe suivant. Son prototype est :
size_t strspn(char *str1, char *str2);

La fonction strspn() recherche dans str1 la position du premier caractre nayant pas dquivalent dans str2 et renvoie cette position, ou NULL si aucune correspondance nest dcouverte. Le programme du Listing 17.12 montre un exemple dutilisation. Listing 17.12 : Recherche du premier caractre nayant pas de correspondance avec strspn()
1:/* Recherche avec strspn(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h>

http://fribok.blogspot.com/

5: 6:int main() 7:{ 8:charbuf1[80], buf2[80]; 9:size_t loc; 10: 11:/* Entre des deux chanes. */ 12:printf("Tapez la chane de caractres dans laquelle \ 13:on cherchera:\n"); 14:lire_clavier(buf1, sizeof(buf1); 15:printf("Tapez la chane de caractres contenant les \ 16:caractres chercher:\n"); 17:lire_clavier(buf2, sizeof(buf2); 18:/* Effectuer la recherche. */ 19: 20:loc = strspn(buf1, buf2); 21: 22:if (loc ==0) 23:printf("On na trouv aucune correspondance.\n"); 24:else 25:printf("Il y a correspondance jusqu la position%d.\n", 26:loc1); 27: exit(EXIT_SUCCESS); 28:}

Le fonctionnement de cette fonction ntant pas vident, voici trois essais qui permettront dy voir plus clair :
Tapez la chane de caractres dans laquelle on cherchera: Le chat de la voisine Tapez la chane de caractres contenant les caractres chercher: Le chat de la cousine Il y a correspondance jusqu la position 13. Tapez la chane de caractres dans laquelle on cherchera: Le chat de la voisine Tapez la chane de caractres contenant les caractres chercher: mur On na trouv aucune correspondance. Tapez la chane de caractres dans laquelle on cherchera: Le chat de la cousine Tapez la chane de caractres contenant les caractres chercher: Le chat de la voisine Il y a correspondance jusqu la position 15.

Analyse La structure du programme tant identique celle de lexemple prcdent, il est inutile de rpter les explications qui ont t donnes cette occasion. En revanche, dans les exemples

http://fribok.blogspot.com/

ci-avant, on voit que dans le premier cas, la premire lettre de str1 nayant pas dquivalent dans str2 est le v qui occupe la position 13. Dans le deuxime cas, str2 ne contient aucune des lettres de str1. Enn, dans le troisime, cest le u de "cousine" qui na aucune correspondance dans str2.

La fonction strpbrk()
La fonction de bibliothque strpbrk() ressemble la fonction strcspn(). Elle recherche, elle aussi, la premire occurrence, dans une chane, dun des caractres dune seconde chane ; mais, en plus, elle inclut le terminateur \0 dans la recherche. Son prototype est :
char * strpbrk(char *str1, char *str2)

Elle renvoie un pointeur vers le premier caractre de str1 qui correspond un caractre quelconque de str2; NULL si aucune correspondance nest trouve. Comme nous venons de le dire pour strchr(), on peut obtenir la position de ce caractre en soustrayant de la valeur de retour (si elle est diffrente de NULL, bien sr) ladresse du dbut de str1.

La fonction strstr()
La dernire, et peut-tre la plus utile, de nos fonctions de manipulation de caractres est strstr(). Elle recherche la premire occurrence dune chane lintrieur dune autre. Cette recherche sapplique la chane complte, et non aux caractres qui la composent. Son prototype est :
char *strstr(char *str1, char *str2);

Elle retourne un pointeur vers la premire occurrence de str2 dans str1, ou NULL si aucune correspondance nest trouve. Si la longueur de str2 est gale zro, la fonction retourne ladresse du dbut de str1. Comme nous venons de le dire plus haut, on peut obtenir la position de ce caractre en soustrayant de la valeur de retour (si elle est diffrente de NULL) ladresse du dbut de str1. Le programme du Listing 17.13 montre un exemple dutilisation. Listing 17.13 : Utilisation de la fonction strstr() pour rechercher une chane dans une autre
1:/* Recherche avec strstr(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:int main()

http://fribok.blogspot.com/

7:{ 8:char *loc, buf1[80], buf2[80]; 9: 10:/* Acquisition des deux chanes. */ 11:printf("Tapez la chane de caractres dans laquelle \ 12:seffectuera la recherche:\n"); 13:lire_clavier(buf1, sizeof(buf1)); 14:printf("Tapez la chane rechercher:\n"); 15:lire_clavier(buf2, sizeof(buf2)); 16: 17:/* Effectuer la recherche. */ 18: 19:loc = strstr(buf1, buf2); 20: 21:if (loc ==NULL) 22:printf("Pas de correspondance."); 23:else 24:printf("%s a t dcouvert la position%d.", buf2, \ 25:loc-buf1); 26: exit(EXIT_SUCCESS); 27:}

Lutilisation de cette fonction tant simple, nous ne donnerons quun seul exemple :
Tapez la chane de caractres dans laquelle seffectuera la recherche: le chat de la voisine Tapez la chane rechercher: vois vois a t dcouvert la position 14.

eils Cons

faire Souvenez-vous que, pour la plupart des fonctions de traitement de chanes, il existe des fonctions quivalentes permettant de spcier le nombre des caractres sur lesquels doit porter la manipulation. Leur nom scrit gnralement sous la forme strnxxx(). Lorsque vous voulez recopier une chane de caractres dont vous connaissez la longueur, prfrez memcpy().

Analyse Pas de commentaire particulier ; on se reportera ventuellement ceux des trois fonctions prcdentes.

http://fribok.blogspot.com/

Conversions de chanes
Il existe deux fonctions pour modier la casse dun caractre :
char *tolwr(char c); char *toupr(char c);

Ces deux fonctions ncessitent linclusion du chier den-tte ctype.h. La premire convertit le caractre fourni en argument de majuscules en minuscules et la seconde fait le contraire. Les caractres accentus subsistent tels quels. Il nexiste pas de fonction dun standard rpandu qui convertisse une chane de caractres. Listing 17.14 : Conversion de casse avec les fonctions tolwr() et toupr()
1:/* Les fonctions de conversion de casse strlwr()et strupr(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5:#include <ctype.h> 6: 7:int main() 8:{ 9:char buf[80]; 10:int i; 11: 12:while (1) 13:{ 14:puts("Tapez une lignede texte ou Entre pour terminer."); 15:lire_clavier(buf, sizeof(buf)); 16: 17:if (strlen(buf) == 0) 18:break; 19: 20:for(i=0; i<strlen(buf); i++) buf[i] = tolower(buf[i]); 21:puts(buf); 22: 23:for(i=0; i<strlen(buf); i++) buf[i] = toupper(buf[i]); 24:puts(buf); 25:} 26:exit(EXIT_SUCCESS); 27:}

Voici un exemple montrant ce qui se passe avec des caractres accentus :


Tapez une ligne de texte ou Entre pour Loeil tait dans la tombe et regardait loeil tait dans la tombe et regardait LOEIL TAIT DANS LA TOMBE ET REGARDAIT Tapez une ligne de texte ou Entre pour terminer. Can. can. CAN. terminer.

http://fribok.blogspot.com/

Fonctions de conversion dune chane de caractres en nombre


Il existe plusieurs fonctions permettant de convertir une chane de caractres en sa reprsentation numrique (ce qui permet de lutiliser dans des calculs). Par exemple, la chane "123" peut tre convertie en un entier int dont la valeur sera gale 123. Leurs prototypes se trouvent dans stdlib.h.

La fonction strtol()
Cette fonction convertit une chane de caractres en une valeur de type long int. Son prototype est :
long int strtol(const char *ptr, char **endptr, int base);

Elle convertit la chane pointe par ptr en un entier sign selon la base indique en troisime argument. Gnralement, vous souhaiterez convertir la chane en base 10. Pour cela, vous mettrez NULL en deuxime argument et 10 en troisime. La fonction strtol() reconnat, outre les chiffres 0 9, les caractres + et . La conversion dbute en tte de la chane et se poursuit jusqu la rencontre dun caractre ne faisant pas partie de lensemble des caractres reconnus. Si la fonction ne reconnat aucun de ces caractres, elle renvoie 0. Pour faire la diffrence entre la conversion de la chane "0" (ou quivalente comme par exemple "-00") et un problme de conversion qui renverrait galement 0, vous devez tester la variable errno que vous aurez mis auparavant 0. Le Tableau 17.2 donne quelques exemples :
Tableau 17.2 : Conversions effectues par strtol()

Chane "157" " 1.8" "+50x" "douze" "x506"

Valeur renvoye 157 1.8 50 0 0

Dans les trois derniers exemples, on vrie que la rencontre dun caractre non numrique et autre quun signe met n la conversion. Le programme du Listing 17.14 montre un exemple dutilisation.

http://fribok.blogspot.com/

Listing 17.14 : Utilisation de la fonction strtol() pour convertir une chane de caractres
1:/* convertion de chane en long avec strtol(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <errno.h> 5: 6:int main() 7:{ 8:char nombre1[] = "123"; 9:char nombre2[] = "-00"; 10:char nombre3[] = "douze"; 11:long n; 12: 13:errno = 0; 14:n = strtol(nombre1, NULL, 10); 15:if(errno) 16:printf("%s nest pas un nombre\n", nombre1); 17:else 18:printf("%s vaut %d\n", nombre1, n); 19: 20:errno = 0; 21:n = strtol(nombre2, NULL, 10); 22:if(errno) 23:printf("%s nest pas un nombre\n", nombre2); 24:else 25:printf("%s vaut %d\n", nombre2, n); 26: 27:errno = 0; 28:n = strtol(nombre3, NULL, 10); 29:if(errno) 30:printf("%s nest pas un nombre\n", nombre3); 31:else 32:printf("%s vaut %d\n", nombre3, n); 33: 34: exit(EXIT_SUCCESS); 35:} 123 vaut 123 -00 vaut 0 douze nest pas un nombre

eils Cons

faire Initialiser errno avant chaque appel strtol(). Vrier par la valeur de errno quil ny a pas eu derreur lors de lappel strtol().

http://fribok.blogspot.com/

ne pas faire Utiliser les fonctions atoi(), atol() et atoll() qui ne font pas la diffrence entre une chane contenant 0 et une chane impossible convertir. Analyse La conversion des chanes de caractres en long seffectue chaque fois de la mme manire avec le deuxime argument de strtol() NULL et le troisime 10. Il faut initialiser la variable externe errno 0 avant chaque appel. Si la chane ne contient pas de nombre, strtol() modie errno. Cest ainsi que lon fait la diffrence entre une chane contenant 0 et une chane qui ne contient pas de nombre. La fonction atoi() effectue galement la conversion mais vous devez lviter car contrairement strtol(), elle ne fait pas la diffrence entre une chane contenant 0 et une chane ne pouvant tre convertie.

La fonction strtoll()
Cette fonction fait le mme travail que strtol(), mais, cette fois, le rsultat de la conversion est de type long long int. Son prototype est :
long long int strtoll(const char *ptr, char **endptr, int base);

La fonction strtoul()
Cette fonction fait le mme travail que strtol(), mais, cette fois, le rsultat de la conversion est non sign, de type unsigned long int. Son prototype est :
unsigned long int strtoul(const char *ptr, char **endptr, int base);

La fonction strtoull()
Cette fonction fait le mme travail que strtoll(), mais, cette fois, le rsultat de la conversion est non sign, de type unsigned long long int. Son prototype est :
unsigned long long int strtoull(const char *ptr, char **endptr, int base);

La fonction strtod()
Cette fonction convertit une chane de caractres en une valeur numrique de type double. Son prototype est :
double strtod(char *ptr, char **endptr);

http://fribok.blogspot.com/

Elle convertit la chane pointe par ptr en un nombre ottant double prcision. Comme avec strtol(), le second argument est peu utile et peut tre mis NULL. cet effet, cette fonction reconnat, outre les chiffres 0 9, les caractres + et , les caractres E et e (exposant) et admet un ou plusieurs blancs en tte. La conversion dbute au dbut de la chane et se poursuit jusqu la rencontre dun caractre ne faisant pas partie de lensemble des caractre reconnus. Si la fonction ne reconnat aucun de ces caractres, elle renvoie 0. Pour faire la diffrence entre la conversion de la chane "0" (ou quivalente comme par exemple "-0.0") et un problme de conversion qui renverrait galement 0, vous devez tester la variable errno que vous aurez mis auparavant 0. Le Tableau 17.3 donne quelques exemples :
Tableau 17.3 : Conversions effectues par strtod()

Chane "12" " 0.123" "125E+3" "123.1e 5"

Valeur renvoye
12.000000 0.123000 123000.000000 0.001231

Listing 17.15 : Utilisation de la fonction strtod()pour convertir une chane de caractres en une valeur numrique de type double
1:/* Dmonstration de strtod(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5:#include <errno.h> 6: 7:int main() 8:{ 9:char buf[80]; 10:double d; 11: 12:while (1) 13:{printf("\nTapez la chane de caractres convertir \ 14:(Entre pour terminer): "); 15:lire_clavier(buf, sizeof(buf)); 16: 17:if (strlen(buf) == 0) 18:break; 19: 20:errno = 0; 21:d = strtod(buf, NULL);

http://fribok.blogspot.com/

22:if(errno) 23:{ 24:printf("Pas de valeur convertir dans la chane\n"); 25:} else { 26:printf("Valeur convertie:%f.", d); 27:} 28:} 29:exit(EXIT_SUCCESS); 30:}

Voici quelques exemples de conversions :


Tapez la chane de caractres convertir 123.45 Valeur convertie: 123.450000. Tapez la chane de caractres convertir 67. Valeur convertie: 67.000000. Tapez la chane de caractres convertir abc Pas de valeur convertir dans la chane Tapez la chane de caractres convertir 0 Valeur convertie: 0.000000. Tapez la chane de caractres convertir (Entre pour terminer):

(Entre pour terminer):

(Entre pour terminer):

(Entre pour terminer):

(Entre pour terminer):

Analyse La boucle while des lignes 12 28 permet de faire plusieurs essais. Aux lignes 14 et 15, on demande lutilisateur de taper une valeur. la ligne 17, on regarde sil a simplement tap Entre, auquel cas, le programme se termine. La variable externe errno est mise zro ligne 20 pour tester une ventuelle erreur ligne 22. La chane de caractres tape est convertie en un nombre ottant la ligne 21, puis afche la ligne 24 ou 26 selon quil y avait quelque chose convertir (ligne 26) ou non (ligne 24)..

La fonction strtof()
Cette fonction fait le mme travail que strtod(), mais, cette fois, le rsultat de la conversion est de type float. Son prototype est :
float strtoull(const char *ptr, char **endptr);

Cette fonction est supporte par les compilateurs reconnaissant la norme ISO C99 mais pas les normes ISO C prcdentes (ANSI et C89). Avec le compilateur gcc, vous devrez ainsi lui indiquer loption std=c99. Il est galement possible dindiquer la macro suivante pour spcier que votre code est conforme cette norme :
#define _ISOC99_SOURCE

http://fribok.blogspot.com/

La fonction sprintf()
Cette fonction est linverse de toutes les fonctions prcdentes. Elle convertit des nombres (et des chanes) en une chane de caractres. Son prototype est :
int sprintf(char *str, const char *format, ...);

Cette fonction, initialement absente du standard ANSI, est largement supporte car conforme aux normes C89 et C99. Elle fonctionne comme fprintf() que nous avons vue aux Chapitres 14 et 16, ceci prs que le premier argument est un pointeur vers une chane de caractres et non un descripteur de ux. Par consquent, vous pouvez indiquer ladresse dun espace mmoire et sprintf() le remplira dune chane en convertissant les donnes suivant le format indiqu en deuxime argument. Dans les exemples suivants, chacune des deux lignes a leffet inverse (on suppose que les pointeurs ont t correctement initialiss vers des espaces mmoires de taille sufsante).

Exemple 1
n = strtol("123", NULL, 10); sprintf(str, "%d", 123);

Exemple 2
d = strtod("11.23", NULL); sprintf(str, "%f", 11.23);

Fonctions de test de caractres


Le chier den-tte ctype.h contient les prototypes dun certain nombre de fonctions de test de caractres qui renvoient vrai ou faux, selon que le caractre test remplit ou non la condition indique. Par exemple : "Est-ce une lettre ou un chiffre ?" Ces fonctions sont en ralit des macros. Ce nest quau Chapitre 21 que vous saurez tout sur les macros et, ce moment, vous pourrez regarder dans ctype.h comment sont dnies les fonctions que nous allons maintenant tudier. Toutes ces macros ont le mme prototype :
int isxxxx(int ch);

o xxx est le nom dune macro particulire et ch, le caractre tester. Le Tableau 17.4 donne la liste de ces macros. Vous pouvez faire des choses trs intressantes laide de ces fonctions. Par exemple, la fonction get int() du Listing 17.17 lit une chane de caractres reprsentant un entier sur stdin, et renvoie une valeur numrique de type int. Elle ignore les espaces en tte et renvoie 0 si le premier caractre rencontr nest pas un chiffre.

http://fribok.blogspot.com/

Tableau 17.4 : Liste des macros isxxxx()

Macro isalnum() isalpha() isascii() iscntrl() isdigit () isgraph () islower () isprint () ispunct () isspace () isupper () isxdigit ()

Action
Renvoie vrai si ch est une lettre ou un chiffre Renvoie vrai si ch est une lettre Renvoie vrai si ch est un caractre ASCII standard (compris entre 0 et 127) Renvoie vrai si ch est un caractre de contrle Renvoie vrai si ch est un chiffre Renvoie vrai si ch est un caractre imprimable (autre quun espace) Renvoie vrai si ch est une lettre minuscule (bas de casse) Renvoie vrai si ch est un caractre imprimable (espace compris) Renvoie vrai si ch est un caractre de ponctuation Renvoie vrai si ch est un sparateur (espace, tabulation, tabulation verticale, la ligne, saut de page ou retour chariot) Renvoie vrai si ch est une lettre majuscule (capitale) Renvoie vrai si ch est un chiffre hexadcimal (0 9 et A F)

Listing 17.17 : Utilisation des macros isxxx() pour implmenter une fonction de lecture au clavier dun nombre entier
1:/* Utilisation des macros de test de caractres pour raliser 2:une fonction lisant un entier au clavier */ 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <ctype.h> 6: 7:int get_int(void); 8: 9:int main() 10:{ 11:int x; 12:x =get_int(); 13:printf("Vous avez tap:%d.\n", x); 14:exit(EXIT_SUCCESS); 15:} 16: 17:int get_int(void) 18:{ 19:int ch, i, sign = 1; 20: 21:/* Ignorer les espaces en tte. */ 22: 23:while (isspace(ch = getchar()))

http://fribok.blogspot.com/

Listing 17.17 : Utilisation des macros isxxx() pour implmenter une fonction de lecture au clavier dun nombre entier (suite)
24:; 25: 26:/* Si le premier caractre nest pas numrique, 27:le recracher et renvoyer 0 */ 28: 29:if (ch!= - && ch!= + &&!isdigit(ch) && ch!= EOF) 30:{ 31:ungetc(ch, stdin); 32:return 0; 33:} 34: 35:/* Si le premier caractre est un signe moins, placer 36:le signe du rsultat. */ 37: 38:if (ch == -) 39:sign = 1; 40: 41:/* Si le premier caractre est un signe+ou un signe , 42:lire le caractre suivant */ 43: 44:if (ch == + || ch == -) 45:ch = getchar(); 46: 47:/* Lire des caractres jusqu en trouver un qui ne soit 48:pas un chiffre. Effectuer la conversion en multipliant 49:chacun des chiffres lus par la bonne puissance de 10 */ 50:for (i = 0; isdigit(ch); ch = getchar()) 51:i = 10 * i+ (ch 0); 52: 53:/* Corriger ventuellement le signe. */ 54: 55:i *= sign; 56: 57:/* Si on na pas rencontr dEOF, cest quon a lu un 58:caractre non numrique. Le recracher. */ 59: 60:if (ch!= EOF) 61:ungetc(ch, stdin); 62: 63:/* Renvoyer la valeur finale. */ 64: 65:return i; 66:} 123 Vous avez BABA57 Vous avez 685 Vous avez 99 9 Vous avez

tap: 123. tap: 0. tap: 685. tap: 9.

http://fribok.blogspot.com/

Analyse Aux lignes 31 et 61, ce programme utilise la fonction ungetc() que nous avons tudie au Chapitre 14, pour "recracher" un caractre qui ne lui convient pas dans le ot dentre, ici stdin. Ce sera le premier lu dans lordre de lecture suivant. Ici, cest la fonction get int() qui est la plus labore, main() ne faisant que lui servir de faire-valoir. La ligne 23 boucle sur un while pour ignorer les espaces placs ventuellement en tte. la ligne 29, on vrie que le caractre lu est un de ceux qui conviennent pour reprsenter un entier. Si ce nest pas le cas, il est recrach la ligne 31 et on revient au programme appelant. Le signe est trait aux lignes 38 45. La variable sign a t dnie comme un int initialis 1. Si on trouve un signe ( ), linstruction situe la ligne 39 lui donne la valeur 1. Il servira multiplier la valeur absolue du nombre, en n de conversion. Si on a lu un signe, il faut continuer lire, en esprant trouver au moins un chiffre (lignes 44 et 45). Le cur de la fonction est constitu par la boucle for des lignes 50 et 51, qui continue lire des caractres (ch = getchar()) tant que ceux-ci sont utilisables [condition terminale : isdigit(ch)]. La conversion seffectue la ligne 51 par linstruction :
i = 10 * i+ (ch 0);

dans laquelle la conversion du caractre en chiffre dcimal seffectue en soustrayant la valeur "caractre" 0 de ch. Nous naurions pas pu crire :
i = 10 * i+strtol(ch, NULL, 10);

puisque ch est un caractre et non une chane de caractres (il nest pas suivi par un terminateur \0). Cest la ligne 55 quon tient compte du signe et le rsultat nal est renvoy la ligne 65, le programme ayant fait un peu de nettoyage entre-temps (si le dernier caractre lu ntait pas lquivalent dun EOF, on le recrache). Si complique soit-elle, cette fonction "oublie" de sassurer que le nombre nal obtenu est bien reprsentable dans un int, cest--dire quil nest pas trop grand.
eils Cons

ne pas faire Utiliser des fonctions non conformes une norme rpandue telle que ANSI, POSIX ou BSD si vous envisagez de porter vos programmes sur dautres platesformes. Confondre les caractres avec les nombres : 1 est diffrent de 1.

http://fribok.blogspot.com/

Rsum
Dans ce chapitre, vous avez pu dcouvrir de nombreuses faons de manipuler des chanes de caractres. laide des fonctions de la bibliothque standard vous pouvez copier, concatner et comparer des chanes de caractres. Vous pouvez aussi y rechercher la prsence de caractres ou de groupes de caractres. Ce sont l des tches quon rencontre dans beaucoup de programmes. La bibliothque standard contient aussi des fonctions de conversion de casse (minuscule en majuscule et inversement) et de conversion de chanes de caractres en valeurs numriques. Enn, il existe des fonctions (plus exactement, des macros) de test de caractres.

Q&R
Q Comment puis-je savoir quune fonction est reconnue par tel ou tel standard ? R La plupart des compilateurs sont fournis avec un manuel de rfrence de leur bibliothque dans lequel vous trouverez la liste des fonctions avec leur description complte. Sur Linux et certains Unix, regardez le volet Conformit des pages de manuel. Q Y a-t-il dautres fonctions de traitement de caractres qui nont pas t prsentes dans ce chapitre ? R Oui, mais celles que nous avons vues couvrent virtuellement tous vos besoins. Consultez le manuel de votre compilateur pour connatre celles qui existent en plus. Q Est-ce que strcat() ignore les espaces ventuels droite en concatnant deux chanes ? R Non. Pour elle, un espace est un caractre comme un autre. Q Puis-je convertir une valeur numrique en chane de caractres ? R Bien sr, avec la fonction sprintf().

Atelier
Latelier vous propose de tester vos connaissances sur les sujets abords dans ce chapitre.

Quiz
1. Quest-ce que la longueur dune chane et comment peut-on en connatre la valeur ? 2. Avant de copier une chane de caractres, de quoi devez-vous vous assurer ? 3. Que signie le terme "concatner" ?

http://fribok.blogspot.com/

4. Lorsque vous comparez des chanes de caractres, que signie "Une des deux chanes est plus grande que lautre" ? 5. Quelle diffrence y a-t-il entre strcmp() et strncmp()? 6. Quelle diffrence y a-t-il entre strcmp() et strcmpi()? 7. Quelles valeurs la fonction isascii() teste-t-elle ? 8. Daprs le Tableau 17.4, quelles sont les macros qui renvoient vrai pour var si cette variable est dnie par :
int var = 1;

9. Daprs le Tableau 17.4, quelles sont les macros qui renvoient vrai pour x si cette variable est dnie par :
char x = 65;

10. quoi servent les fonctions de test de caractres ?

Exercices
1. Quelles valeurs renvoient les fonctions de test ? 2. Que va renvoyer la fonction strtol(valeur, NULL, 10) si on lui passe les valeurs suivantes : a) "65". b) "81.23". c) "34.2". d) "dix". e) "+12mille". f) "moins100". 3. Que va renvoyer la fonction strtod(valeur, NULL) si on lui passe les valeurs suivantes : a) "65". b) "81.23". c) "34.2". d) "dix". e) "+12mille". f) "1e+3".

http://fribok.blogspot.com/

4. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions qui suivent ?
char *string1, string2; string1 = "Hello, World"; strcpy(string2, string1); printf("%s%S", string1, string2);

Pour les exercices qui suivent, il y a plusieurs solutions possibles. Nous nen donnerons pas le corrig. 5. crivez un programme qui demande lutilisateur son nom, son premier prnom et son second prnom (sil en a un). Placez-les ensuite tous trois dans une chane de caractres sous la forme : initiale du prnom, point, espace, initiale du second prnom, point, espace et nom. Par exemple, si lutilisateur a tap "Jules Oscar Hamel", vous devez obtenir "J. O. Hamel". Afchez le rsultat. 6. crivez un programme qui prouve vos rponses aux questions 8 et 9 du quiz. 7. La fonction strstr() trouve la premire occurrence dune chane lintrieur dune autre chane et diffrencie les minuscules des majuscules. crivez une fonction qui fasse la mme chose sans distinguer les minuscules des majuscules. 8. crivez une fonction qui compte le nombre doccurrences dune chane lintrieur dune autre chane. 9. crivez un programme qui cherche dans un chier texte les occurrences dune chane de caractres spcie par lutilisateur, et afche les numros des lignes rpondant au critre. Par exemple, si vous recherchez dans un de vos programmes C les occurrences de la chane printf, votre programme devra afcher toutes les lignes faisant appel la fonction printf(). Sur Unix, contrlez le rsultat avec la commande grep qui effectue la mme chose. 10. crivez une fonction get float() analogue celle du Listing 17.17, mais donnant le rsultat sous forme de nombre ottant.

http://fribok.blogspot.com/

18
Retour sur les fonctions
Comme vous avez d vous en apercevoir, les fonctions constituent lun des lments les plus importants de la puissance et de la souplesse du langage C. Dans ce chapitre, nous allons voir les points suivants :

Utilisation de pointeurs comme arguments de fonction Passage de pointeurs de type void en arguments Utilisation de fonctions avec un nombre variable darguments Renvoi dun pointeur par une fonction

Nous avons dj tudi certains de ces sujets dans les chapitres prcdents, mais nous allons y revenir plus en dtail dans ce chapitre.

http://fribok.blogspot.com/

Passage de pointeurs une fonction


La mthode par dfaut pour passer un argument une fonction est un passage par valeur, ce qui signie que la fonction reoit une copie de la valeur de largument. Cette mthode se ralise en trois tapes : 1. Lexpression passer en argument est value (ou prise telle quelle sil sagit dune constante ou dune variable). 2. Le rsultat est recopi sur la pile (stack) qui est une zone de stockage temporaire en mmoire. 3. La fonction rcupre la valeur de largument sur la pile. Cette procdure est illustre par la Figure 18.1 avec un seul argument : une variable de type int; mais la mthode est la mme pour dautres types de variables et des expressions plus complexes.
Figure 18.1 Passage dun argument par valeur. La fonction ne peut pas modier la valeur originale de la variable.
w = half (x); x 1000 1001 1002 1003 16 int half (int y) { return y/2; }

. . . . . . . . . . . . . . . . . . .

La valeur de x est copie sur la pile

16

La fonction peut accder la valeur de x

Mmoire Pile

Lorsquune variable est passe une fonction par valeur, la fonction a accs la valeur de la variable, mais pas la variable elle-mme. Il en rsulte que la fonction ne peut pas modier la valeur originale de cette variable. Cest la principale raison dutiliser un passage dargument par valeur. Les donnes situes lextrieur dune fonction sont protges de toute altration accidentelle. Ce mode de transmission darguments est possible avec les types de donnes de base (char, long, float et double) et les structures. Il existe, cependant, une mthode pour passer des arguments une fonction, consistant passer un pointeur vers la variable

http://fribok.blogspot.com/

originale et non vers une copie de sa valeur. Cette mthode est appele passage par adresse (ou par rfrence). Comme nous lavons vu au Chapitre 9, ce type de passage est le seul utilisable pour les tableaux. Les variables simples et les structures peuvent tre transmises indiffremment par les deux mthodes. Si votre programme utilise de grosses structures, les passer par valeur risquerait dentraner un dbordement de la pile. Passer un argument par adresse permet la fonction de modier la valeur originale de la variable, ce qui est la fois un avantage et un inconvnient. Que ce soit la fois un avantage et un inconvnient ne doit pas vous tonner. Tout dpend de la situation dans laquelle on se trouve. Si le programme a besoin de modier la valeur de la variable, alors, cest un avantage. Si ce nest pas le cas, cela peut dgnrer en inconvnient. Il existe une faon bien simple de modier la valeur dun argument, comme le montrent ces quelques lignes de programme :
x = f(x) int f(int y) { return y/2; }

Souvenez-vous quune fonction ne peut renvoyer quune seule valeur. En passant un ou plusieurs arguments par adresse, permettez une fonction de renvoyer plusieurs rsultats au programme qui l a appele. La Figure 18.2 illustre le passage par adresse dun seul argument.
Figure 18.2 Le passage par adresse permet la fonction de modier la valeur originale de la variable.
half (&x); 1000 1001 1002 1003 16 void half (int *y { *y = *y/2; } x

. . . . . . . . . . . . . . . . . . .

L'adresse de x est copie sur la pile

1000

Si la fonction connat l'adresse d'une variable, elle peut y accder.

Mmoire Pile

http://fribok.blogspot.com/

La fonction utilise pour la Figure 18.2 ne donne pas un bon exemple dutilisation dun appel par adresse dans un vritable programme, mais elle illustre bien le concept. Lorsque vous passez un argument par adresse, il faut vous assurer que le prototype de la fonction indique bien cette mthode de passage (on passe non plus une valeur, mais un pointeur). Dans le corps de la fonction, vous devrez aussi utiliser loprateur dindirection pour accder la variable (ou aux variables) passe(s) par adresse. Le programme du Listing 18.1 montre un passage darguments par adresse et par valeur, et prouve clairement que cette dernire mthode ne permet pas daltrer la valeur initiale de la variable. Bien entendu, une fonction nest pas oblige de modier la valeur dun argument transmis par adresse, mais "elle peut le faire". Listing 18.1 : Passage par valeur et passage par adresse
1:/* Passage darguments par valeur et par adresse. 2:*/ 3:#include <stdio.h> 4:#include <stdlib.h> 5:void par_valeur(int a, int b, int c); 6:void par_adresse(int *a, int *b, int *c); 7: 8:int main() 9:{ 10:int x = 2, y = 4, z = 6; 11: 12:printf("\nAvant dappeler par_valeur (), x =%d, y =%d,\ 13:z =%d.", x, y, z); 14: 15:par_valeur(x, y, z); 16: 17:printf("\nAprs avoir appel par_valeur(), x =%d, y =%d, 18:z =%d.", x, y, z); 19: 20:par_adresse(&x, &y, &z); 21:printf("\nAprs avoir appel par_adresse(), x =%d, y =%d, 22:z =%d.\n", x, y, z); 23:exit(EXIT_SUCCESS); 24:} 26:void par_valeur(int a, int b, int c) 27:{ 28:a = 0; 29:b = 0; 30:c = 0; 31:} 32:

http://fribok.blogspot.com/

33:void par_adresse(int *a, int *b, int *c) 34:{ 35:*a = 0; 36:*b = 0; 37:*c = 0; 38:} Avant dappeler par_valeur (), x = 2, y = 4, z = 6. Aprs avoir appel par_valeur(), x = 2, y = 4, z = 6. Aprs avoir appel par_adresse(), x = 0, y = 0, z = 0.

Analyse Ce programme montre la diffrence entre les deux mthodes de passage darguments. Les lignes 5 et 6 contiennent les prototypes des deux fonctions quappellera le programme. La premire comporte une liste darguments "ordinaires", de type int: cest lappel "par valeur" (comme lindique le nom de la fonction). La liste des arguments de lautre fonction est une liste de pointeurs. Il sagit dappels "par adresse". Aux lignes 26 et 33, la premire instruction de chacune des fonctions respecte la dclaration faite par le prototype. On fait la mme chose dans le corps de ces fonctions, mais on ne le fait pas de la mme faon. Les deux fonctions remettent 0 les variables transmises. Dans la premire, il sagit des copies, places sur le stack, des valeurs originales ; dans la seconde, on remet zro les variables elles-mmes, dans le programme appelant. la ligne 12, on afche les valeurs originales des variables. Ensuite, la ligne 15, on appelle la fonction par valeur() et on rafche les valeurs des variables la ligne 17. On remarque quelles nont pas chang. la ligne 20, on appelle la fonction par adresse() puis, la ligne 22, on rafche les valeurs. On constate alors quelles valent bien zro. La preuve est faite quon peut modier les valeurs des variables du programme appelant. Il est possible de mlanger les deux types de passage darguments dans un mme appel de fonction. Il faudra bien faire attention, en appelant plus tard la fonction, ne pas les mlanger.
eils Cons

faire Passer des variables par valeur pour ne pas risquer de les voir modies par la fonction appele. ne pas faire Passer de grandes quantits de variables par valeur lorsque ce nest pas ncessaire. Vous risqueriez de faire dborder la pile.

http://fribok.blogspot.com/

Oublier quune variable passe par adresse doit tre crite sous forme de pointeur. Dans la fonction, vous devrez utiliser loprateur dindirection pour rcuprer sa valeur.

Les pointeurs de type void


Vous avez dj rencontr le mot cl void servant indiquer quune fonction ne renvoie pas de valeur ou ne demande pas dargument. On peut aussi lutiliser pour dclarer un pointeur de type gnrique, cest--dire pouvant pointer vers nimporte quel type dobjet. Par exemple, linstruction :
void *x;

dclare un pointeur gnrique x, pointant vers un objet dont on na pas encore spci le type. Lusage le plus frquent de ce type de pointeurs se rencontre dans une dclaration des arguments dune fonction. Vous pouvez souhaiter crer une fonction capable de prendre en compte diffrents types darguments : int, float, etc. En dclarant le pointeur vers cet argument comme tant de type void, vous pouvez utiliser plusieurs types darguments. Voici un exemple simple. Vous voulez crire une fonction, demi() calculant la moiti de la valeur qui lui est passe, et vous voulez que son rsultat soit du mme type. Outre la valeur elle-mme, vous lui passez un caractre indiquant le type de largument (i pour int, f pour float, etc.). La fonction sera alors dclare de la faon suivante :
void demi(void *x, char type);

Mais, avoir pass un pointeur est une chose, pouvoir rcuprer correctement la valeur vers laquelle il pointe en est une autre. Il faut, pour cela, caster ce pointeur an que le compilateur sache quoi sen tenir et fasse son travail correctement. Dans le cas dun entier, par exemple, on crira :
(int *) x

et pour accder la valeur de la variable, il faut rajouter loprateur dindirection. Cela donne :
* (int *) x

Le casting sera approfondi au Chapitre 20. Pour notre exemple, nous avons retenu quatre types de variables : int, long, float et double, indiqus respectivement par leur initiale sous forme de constante caractre.

http://fribok.blogspot.com/

Le Listing 18.2 vous prsente la fonction demi() accompagne dun main() simple pour la tester. Listing 18.2 : Utilisation dun pointeur de type void pour passer des variables de types diffrents une fonction
1:/* Utilisation de pointeurs de type void. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:void demi(void *x, char type); 6: 7:int main() 8:{ 9:/* Initialiser une variable de chaque type. */ 10: 11:int i = 20; 12:long l = 100000L; 13:float f = 12.456; 14:double d = 123.044444; 15: 16:/* Afficher leur valeur initiale. */ 17: 18:printf("\n%d", i); 19:printf("\n%ld", l); 20:printf("\n%f", f); 21:printf("\n%lf\n\n", d); 22: 23:/* Appeler demi() pour chaque variable. */ 24: 25:demi(&i, i); 26:demi(&l, l); 27:demi(&d, d); 28:demi(&f, f); 29: 30:/* Afficher leur nouvelle valeur. */ 31:printf("\n%d", i); 32:printf("\n%ld", l); 33:printf("\n%f", f); 34:printf("\n%lf", d); 35:exit(EXIT_SUCCESS); 36:} 37: 38:void demi(void *x, char type) 39:{ 40:/* Caster la valeur de x selon le type de x et faire 41:la division par 2 */ 42: 43:switch (type) 44:{ case i: 45:*(int *) x /= 2; 46:break; 47:case l: 48:*(double *) x /= 2L;

http://fribok.blogspot.com/

Listing 18.2 : Utilisation dun pointeur de type void pour passer des variables de types diffrents une fonction (suite)
49:break; 50:case f: 51:*(float *) x /= 2.; 52:break; 53:case d: 54:*(double *) x /= 2.0; 55:break; 56:} 57:} 20 100000 12.456000 123.044444

5 50000 6.228000 61.522222

Analyse Pour simplier, on ne fait aucun test de validit, ni sur les arguments, ni sur lindicateur de type. Il aurait t prudent de rajouter une clause default au switch:
default: printf("%c: type inconnu.\n", type);

(Rappelons quil est inutile de terminer cette clause par un break; puisque cest la dernire du switch.) Vous pourriez penser que la ncessit de passer le type de variable en plus de sa valeur diminue la souplesse de cette fonction, et quelle aurait t plus gnrale sans cette indication complmentaire. Malheureusement, C ne dispose pas dune boule de cristal lui permettant de deviner le type de la variable qui lui est passe. Dans le mcanisme de transmission des arguments, il na pas t prvu dindicateur de type. Il faut donc y suppler par des astuces comme celle que nous venons de voir. On pourrait rcrire cette fonction sous forme de macro. Nous le ferons au Chapitre 21. Comme on ne connat pas la longueur de la variable sur laquelle pointe le pointeur de type void, on ne peut ni lincrmenter, ni le dcrmenter. (En effet, si p est un pointeur de type void, sizeof(*p) na pas de sens et ne peut servir qu fcher le compilateur.)

http://fribok.blogspot.com/

eils Cons

faire Penser caster le pointeur de type void pour utiliser la valeur sur laquelle il pointe. Matriser ses arguments : il est rare davoir indiquer le type des arguments. En loccurrence, de toutes les fonctions standard que nous avons vues, seules celles de la famille de printf() utilisent ce principe. ne pas faire Tenter dincrmenter ou de dcrmenter un pointeur de type void. Utiliser des pointeurs de type void tort et travers.

Fonctions avec un nombre variable darguments


Vous avez souvent utilis des fonctions de bibliothque (printf() et scanf(), par exemple) dont le nombre darguments est variable. Vous pouvez crire de telles fonctions vousmme. Il faudra alors inclure le chier d en-tte stdarg.h. Pour dclarer une fonction admettant un nombre variable darguments, commencez par faire apparatre les arguments xes : ceux qui doivent toujours gurer (il doit y en avoir au moins un). Ensuite, crivez une ellipse, cest--dire trois points la suite, pour indiquer la prsence dun nombre variable darguments, ventuellement nul. Il faut que la fonction ait un moyen de savoir combien darguments lui ont t passs chaque appel. On pourrait songer inclure, parmi les arguments de la fonction, une variable qui spcierait ce nombre. Outre linlgance de ce procd, cela ne mettrait pas lutilisateur labri dune erreur dans le comptage de ses arguments, et terait beaucoup de sret et de rigueur aux programmes quil pourrait crire. On pourrait aussi, comme dans printf(), tabler sur les spcicateurs de conversion (% quelque chose) pour connatre le nombre des variables qui suivent le format. Mais, on retrouve le mme inconvnient que prcdemment. Et cela ne permettrait pas la reconnaissance du type des variables transmises. Bien sr, avec la "mthode" printf, on pourrait le dduire de lindicateur de conversion. Mais, tout cela reste du bricolage et il sagit l dun cas trs particulier partir duquel on ne peut pas gnraliser. Heureusement, le C propose des outils pour raliser, avec lgance et scurit, ce passage darguments en nombre variable. Ces outils se trouvent dans stdarg.h et sont les suivants : va list va start()
Type de pointeur vers des donnes. Macro servant initialiser la liste des arguments.

http://fribok.blogspot.com/

va arg() va end()

Macro servant rcuprer chaque argument, tour tour, de la liste des variables. Macro servant "faire du nettoyage", une fois tous les arguments rcuprs.

Pour bien utiliser ces outils, il faut respecter attentivement les tapes suivantes, illustres par le programme du Listing 18.3 : 1. Dclarez un pointeur de type va list. Il servira accder aux arguments individuels. Bien que ce ne soit pas obligatoire, il est dusage de lappeler arg ptr. 2. Appelez la macro va start() en lui passant va list ainsi que le nom du dernier argument xe. Cette macro ne renvoie pas de valeur : elle se contente dinitialiser le pointeur arg ptr, qui va ensuite pointer vers le premier argument de la liste variable. 3. Pour rcuprer, tour tour, chacun des arguments, appelez va arg() en lui passant le pointeur arg ptr et le type de donnes de largument suivant (int, long, double...). La valeur de retour de va arg() est la valeur de largument suivant. Si la fonction a t appele avec n arguments dans la liste variable, vous devrez appeler n fois va arg() et vous rcuprerez, dans lordre o ils ont t crits, les arguments de la liste variable. 4. Quand vous avez rcupr tous les arguments de la liste variable, il faut "fermer la liste" et, pour cela, appeler va end() en lui passant le pointeur arg ptr. Dans certaines implmentations, cette macro ne fait rien ; dans dautres, elle dblaie le terrain. Quoi quil en soit, il faut systmatiquement lappeler sous peine daboutir la ralisation de programmes non portables. La fonction moyenne() du Listing 18.3 calcule la moyenne arithmtique dune suite de nombres entiers. Ce programme transmet la fonction un argument xe, en indiquant le nombre darguments supplmentaires suivi de la liste des nombres. Listing 18.3 : Utilisation dune liste darguments variables
1:/* Fonctions avec un nombre variable darguments. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <stdarg.h> 5: 6:float moyenne(int num, ...); 7: 8:int main() 9:{ 10:float x; 11: 12:x = moyenne(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

http://fribok.blogspot.com/

13:printf("\nLa premire moyenne est%f.", x); 14:x = moyenne(5, 121, 206, 76, 31, 5); 15:printf("\nLa seconde moyenne est%f.\n", x); 16:exit(EXIT_SUCCESS); 17:} 18: 19:float moyenne(int num, ...) 20:{ 21:/* Dclarer une variable de type va_list. */ 22: 23:va_list arg_ptr; 24:int count, total = 0; 25: 26:/* Initialiser le pointeur vers les arguments. */ 27: 28:va_start(arg_ptr, num); 29: 30:/* Rcuprer chaque argument de la liste variable. */ 31: 32:for (count = 0; count < num; count++) 33:total += va_arg(arg_ptr, int); 34: 35:/* Donner un coup de balai. */ 36: 37:va_end(arg_ptr); 38: 39:/* Diviser le total par le nombre de valeurs moyenner. 40:Caster le rsultat en float puisque cest le type 41:du rsultat.*/ 42: 43:return ((float)total/num); 44:}

Voici le rsultat obtenu :


La premire moyenne est 5.500000. La seconde moyenne est 87.800000.

Analyse La fonction moyenne() est appele une premire fois la ligne 12. Le premier argument pass, le seul qui soit constant, spcie le nombre de valeurs de la liste variable. Cest aux lignes 32 et 33 que vont avoir lieu la rcupration et la sommation de chacun des arguments. Une fois tous les arguments rcuprs, la ligne 43 opre une division par le nombre dlments, et caste le rsultat en float avant de le renvoyer au programme appelant. la ligne 28, on appelle va start() pour initialiser le mcanisme de rcupration. Cet appel doit prcder les appels va arg(). Enn, la ligne 37, on referme par un appel va end() qui fera ventuellement un peu de nettoyage.

http://fribok.blogspot.com/

En ralit, une fonction na pas ncessairement besoin de placer le nombre darguments dans la liste de ses arguments. On pourrait imaginer dautres systmes de dlimitations : une dernire valeur ngative ou nulle, lorsquaucun des lments de la liste ne risque de ltre. Mais faire gurer en tte de liste le nombre darguments est une mthode plus gnrale ; cest celle qui doit normalement tre employe.

Fonctions renvoyant un pointeur


Vous avez dj rencontr, dans la bibliothque standard, des fonctions renvoyant un pointeur au programme qui les a appeles. Rien ne vous empche dcrire de telles fonctions. Comme vous pouvez vous y attendre, loprateur dindirection (*) est utilis la fois dans la dclaration de la fonction et dans sa dnition. Voici quelle en est la forme gnrale :
type *fonc(liste darguments);

Cette instruction dclare une fonction fonc() qui renvoie un pointeur vers un type. En voici deux exemples concrets :
double *fonc1(liste darguments); struct adresse *fonc2(liste darguments);

La premire ligne dclare une fonction qui renvoie un pointeur vers un type double. La seconde ligne dclare une fonction qui renvoie un pointeur vers un type adresse (suppos dni par lutilisateur). Ne confondez pas une fonction qui renvoie un pointeur avec un pointeur vers une fonction. Si vous mettez une paire de parenthses supplmentaire dans la dclaration, cest la dernire forme que vous dclarez, comme on le voit dans ces deux exemples :
double (*fonc)(...); // pointeur vers une fonction qui renvoie un double double *fonc(...);// fonction qui renvoie un pointeur vers un double

Maintenant que nous savons dclarer correctement notre fonction, une question se pose. Comment allons-nous lutiliser ? Il ny a rien de spcial prciser au sujet de ces fonctions : on les utilise comme nimporte quelle autre fonction, en assignant leur valeur de retour une variable du type appropri (donc un pointeur). Comme, en C, un appel de fonction est une expression, vous pouvez vous en servir nimporte quel endroit de votre programme. Le Listing 18.4 prsente un exemple simple. Il sagit dune fonction laquelle on passe deux arguments et qui dtermine et renvoie le plus grand. On verra quil y a en ralit deux exemples : lun retourne un int; lautre, un pointeur vers un int.

http://fribok.blogspot.com/

Listing 18.4 : Renvoi dun pointeur par une fonction


1:/* Fonction qui retourne un pointeur. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:int superieur1(int x, int y); 6:int *superieur2(int *x, int *y); 7: 8:int main() 9:{ 10:int a, b, plusgrand1, *plusgrand2; 11: 12:printf("Tapez deux nombres entiers: "); 13:scanf("%d%d", &a, &b); 14: 15:plusgrand1 = superieur1(a, b); 16:printf("\nCelui qui a la plus grande valeur est:%d.", 17:plusgrand1); 18:plusgrand2 = superieur2(&a, &b); 19:printf("\nCelui qui a la plus grande valeur est:%d.\n", 20:*plusgrand2); 21:exit(EXIT_SUCCESS); 22:} 23:int superieur1(int x, int y) 24:{ 25:if (y > x) 26:return y; 27:return x; 28:} 29: 30:int *superieur2(int *x, int *y) 31:{ 32:if (*y > *x) 33:return y; 34: 35:return x; 36:} Tapez deux nombres entiers: 11113000 Celui qui a la plus grande valeur est: 3000. Celui qui a la plus grande valeur est: 3000.

Analyse La logique de ce programme nexige pas de grandes explications. On sattardera un peu sur lcriture des deux fonctions : superieur1() et superieur2(). Si celle de la premire est dun type "classique", pour la seconde, on voit quon a fait usage de pointeurs la fois pour les arguments et pour le rsultat.

http://fribok.blogspot.com/

Bien entendu, lappel de superieur2() doit tre fait avec des valeurs transmises par adresse (ligne 18) et lafchage du rsultat (ligne 19) ncessite lemploi de loprateur dindirection (*).
eils Cons

faire Utiliser les lments que nous venons dtudier pour crire des fonctions avec un nombre variable darguments, mme si le compilateur nexige pas tous ces lments. Encadrer les appels va arg() par un appel initial va start() et un appel nal va end(). ne pas faire Confondre un pointeur vers une fonction avec une fonction qui renvoie un pointeur.

Rsum
Dans ce chapitre, vous avez tudi quelques particularits concernant les fonctions : la diffrence entre passer des arguments par valeur et les passer par adresse. Vous avez vu comment cette dernire technique permettait une fonction de renvoyer plusieurs rsultats. Vous avez appris utiliser le type void pour crer un pointeur gnrique capable de pointer sur nimporte quel objet de donnes du langage C. Ce type de pointeur est le plus souvent utilis avec des fonctions auxquelles on peut passer des arguments de types diffrents. Rappelez-vous quil est ncessaire de caster un pointeur de type void avant de pouvoir utiliser lobjet sur lequel il pointe. Vous avez dcouvert les macros contenues dans stdarg.h et vous savez maintenant comment les utiliser pour crer des fonctions admettant un nombre variable darguments. Ces fonctions apportent beaucoup de souplesse la programmation. Enn, nous avons vu ce qutait une fonction renvoyant un pointeur et comment lutiliser.

Q&R
Q Est-il courant, lorsquon programme en C, de passer des pointeurs ? R Absolument ! Dans beaucoup de cas, une fonction a besoin de modier plusieurs variables. Il y a deux faons dy parvenir. La premire consiste dclarer et utiliser des variables globales. La seconde, passer des pointeurs de faon que la fonction puisse

http://fribok.blogspot.com/

directement modier les variables ; la premire option est surtout intressante si plusieurs fonctions utilisent les mmes variables (voir Chapitre 12). Q Vaut-il mieux modier une valeur en la renvoyant ou en passant un pointeur sur elle ? R Quand il ny a quune valeur modier dans une fonction, il est dusage de se servir pour cela de la valeur de retour. En revanche, si vous devez changer la valeur de plusieurs variables, soit vous utilisez les structures en renvoyant un pointeur sur une, soit vous passez un pointeur sur ces variables.

Atelier
Latelier vous propose quelques questions permettant de tester vos connaissances sur les sujets que nous venons daborder dans ce chapitre.

Quiz
1. Lorsque vous passez des arguments une fonction, quelle est la diffrence entre les passer par valeur et les passer par adresse ? 2. Quest-ce quun pointeur de type void? 3. Pour quelle raison utilise-t-on un pointeur de type void? 4. Lorsque vous utilisez un pointeur de type void, pour quelle raison emploie-t-on un casting et quand doit-on le faire ? 5. Pouvez-vous crire une fonction ne contenant quune liste variable darguments, sans argument dni une fois pour toutes ? 6. Quelles macros devez-vous utiliser lorsque vous crivez des fonctions ayant une liste darguments variable ? 7. Quelle est la valeur ajoute un pointeur de type void lorsquil est incrment ? 8. Est-ce quune fonction peut renvoyer un pointeur ?

Exercices
1. crivez le prototype dune fonction qui renvoie un entier. Elle aura comme argument un pointeur vers un tableau de caractres. 2. crivez un prototype pour une fonction appele nombres() qui accepte trois entiers comme arguments, lesquels seront passs par adresse.

http://fribok.blogspot.com/

3. Comment cririez-vous linstruction dappel de la fonction nombres() de lexercice prcdent avec trois entiers : ent1, ent2 et ent3? 4. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions qui suivent ?
void carre(int *nombre, ...) { *nombre *= *nombre; }

5. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions qui suivent ?
float total(int nombre, ...) { int compte, total=0; for (compte=0; compte<nombre; compte++) total += va_arg(arg_ptr, int); return total; }

Les exercices suivants admettent plusieurs solutions. Nous nen donnerons pas les corrigs. 6. crivez une fonction laquelle on passe un nombre variable de chanes de caractres en argument, qui concatne ces chanes, dans lordre, en une seule et unique chane et renvoie un pointeur vers la nouvelle chane. 7. crivez une fonction laquelle on passe un tableau de nombres de nimporte quel type en argument, qui recherche le plus grand et le plus petit des nombres du tableau et renvoie des pointeurs vers ces valeurs. (Aide : Vous devrez trouver un moyen dindiquer cette fonction combien il y a dlments dans le tableau.) 8. crivez une fonction qui accepte une chane de caractres et un caractre isol. Elle recherche la premire occurrence du caractre dans la chane et renvoie un pointeur vers cet emplacement.

http://fribok.blogspot.com/

19
Exploration de la bibliothque des fonctions
Comme vous lavez vu tout au long de ce livre, une grande partie de la puissance de C vient de la bibliothque standard des fonctions. Dans ce chapitre, nous allons tudier des fonctions qui nentrent pas dans les sujets abords par les autres chapitres :

Les fonctions mathmatiques Les fonctions qui concernent le temps Les fonctions de traitement derreur Les fonctions de recherche de donnes et de tri

http://fribok.blogspot.com/

Les fonctions mathmatiques


La bibliothque standard contient un certain nombre de fonctions destines raliser des oprations mathmatiques. Leurs prototypes se trouvent dans le chier d en-tte math.h. Toutes renvoient un rsultat de type double. En ce qui concerne les fonctions trigonomtriques, elles portent sur des angles exprims en radians. Souvenez-vous quun radian vaut 180 / 3.14159265, soit 57, 296.

Fonctions trigonomtriques
Fonction acos() asin() atan() atan2() cos() sin() tan() Prototype double acos(double x) double asin(double x) double atan(double x)
double atan2 (double x, double y)

Description
Renvoie larc cosinus dun argument x tel que 1 <= x <= 1 Renvoie larc sinus dun argument x tel que 1 <= x <= 1 Renvoie larc tangente de largument x Renvoie larc tangente du rapport x/y Renvoie le cosinus de largument x Renvoie le sinus de largument x Renvoie la tangente de largument x

double cos(double x) double sin(double x) double tan(double x)

Fonctions logarithmiques et exponentielles


Fonction exp() log() log10() frexp () Prototype double exp(double x) double log(double x) double log10(double x) double frexp(double x, int *y) Description
Renvoie ex (e = 2,71828) Renvoie le logarithme naturel de x Renvoie le logarithme vulgaire (base 10) de x Dcompose x en une fraction normalise (reprsente par la valeur de retour) et une puissance entire de 2, y. Si x = 0, les deux parties du rsultat valent 0 Renvoie x multipli par 2y

ldexp()

double ldexp(double x, int y)

http://fribok.blogspot.com/

Fonctions hyperboliques
Fonction cosh() sinh() tanh() Prototype double cosh(double x) double sinh(double x) double tanh(double x) Description
Renvoie le cosinus hyperbolique de largument x Renvoie le sinus hyperbolique de largument x Renvoie la tangente hyperbolique de largument x

Autres fonctions mathmatiques


Fonction sprt() ceil() abs() labs() floor() modf () Prototype double sqrt(double x) double ceil(double x) int abs(int x long abs(long x) double floor(double x) double modf(double x, double *y) Description
Renvoie la racine carre de largument x qui doit tre positif ou nul Renvoie le plus petit entier suprieur ou gal largument x Renvoie la valeur absolue de largument x Renvoie la valeur absolue de largument x Renvoie le plus grand entier infrieur ou gal largument x Dcompose x en parties entire et dcimale (du mme signe que x). La partie entire est retourne dans lobjet point par y, et la partie dcimale est la valeur de retour Renvoie xy. Il y aura une erreur de domaine si x est ngatif ou nul et si y nest pas un entier ou si x = 0 et que y est ngatif ou nul Renvoie le reste de x/y avec le signe de x, ou 0 si x est nul

pow ()

double pow(double x, double y) double fmod(double x, double y)

fmod ()

http://fribok.blogspot.com/

Exemples
Un livre entier ne sufrait pas pour illustrer toutes les utilisations possibles des fonctions mathmatiques. Le Listing 19.1 ne donne que quelques exemples. Listing 19.1 : Utilisation des fonctions mathmatiques de la bibliothque standard
1:/* Exemples dutilisation de quelques fonctions mathmatiques. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <math.h> 5: 6:int main() 7:{ 8: 9:double x; 10: 11:printf("Tapez un nombre: "); 12:scanf("%lf", &x); 13: 14:printf("\n\nValeur originale:%lf", x); 15: 16:printf("\nCeil:%lf", ceil(x)); 17:printf("\nFloor:%lf", floor(x)); 18:if(x >= 0) 19:printf("\nRacine carre:%lf", sqrt(x)); 20:else 21:printf("\nNombre ngatif."); 22: 23:printf("\nCosinus:%lf\n", cos(x)); 24:exit(EXIT_SUCCESS); 25:} Tapez un nombre:100.95 Valeur originale: 100.950000 Ceil: 101.000000 Floor: 100.000000 Racine carre: 10.047388 Cosinus: 0.913482

Analyse La valeur entre la ligne 12 est afche puis envoye quatre fonctions mathmatiques. On notera quun test est effectu sur le signe de cette valeur avant den prendre la racine carre.

http://fribok.blogspot.com/

Prenons le temps...
La bibliothque standard contient plusieurs fonctions relatives au temps. En langage C, le temps reprsente aussi bien la date que lheure. Les prototypes et la dnition de la structure de ces fonctions se trouvent dans le chier den-tte time.h.

Reprsentation du temps
Les fonctions C utilisent deux types de reprsentation du temps. La plus simple est le nombre de secondes coules depuis le 1er janvier 1970 0 h 00 sur le mridien de Greenwitch (soit 1 h du matin le mme jour dans le fuseau horaire de Paris). Pour les dates antrieures, la valeur est ngative. Ces valeurs sont stockes dans des variables de type long. Dans time.h, les symboles time t et clock t sont dnis comme tant de type long, par un typedef. Ce sont eux qui sont utiliss dans les prototypes des fonctions aux lieu et place de long. La seconde mthode reprsente le temps en le dcomposant en anne, mois, jour, etc. On utilise alors une structure tm ainsi dnie :
struct tm { inttm_sec;// inttm_min;// inttm_hour;// inttm_mday;// inttm_mon;// inttm_year;// inttm_wday;// inttm_yday;// inttm_isdst;// }; secondes [0,61] minutes [0,59] heure [0,23] jour du mois [1, 31] mois [1, 12] annes depuis 1900 jour de la semaine depuis dimanche [0, 6] jour depuis le 1er janvier [0, 165] indicateur dheure dt

On ne manquera pas de stonner de lintervalle [0, 61] prvu pour la valeur de tm sec. Il permet dinsrer un ajustement aux secondes intercalaires apportes parfois la dure de lanne, pour compenser le ralentissement de la dure de rotation de la Terre.

Fonctions traitant du temps


Nous allons tudier les diffrentes fonctions de la bibliothque standard qui traitent du temps. Ici, le mot "temps" se rfre aussi bien la date qu lheure.

Date et heure actuelles


Pour avoir le temps courant tel quil est maintenu par lhorloge interne de votre ordinateur, il faut appeler la fonction time(). Voici son prototype :
time_t time(time_t *timeptr);

http://fribok.blogspot.com/

Rappelez-vous que time h est un alias de long. La fonction renvoie le nombre de secondes coules depuis le 1er janvier 1970. Si vous lui passez un pointeur non nul, elle renseigne la structure time t pointe par timeptr. Ainsi, pour obtenir les valeurs du temps courant (maintenant) dans la structure de type time t, il suft dcrire :
time_t maintenant; maintenant = time(0);

Mais vous auriez aussi pu crire :


time_t maintenant; time_t *m = &maintenant; time(m);

Conversion entre les deux reprsentations du temps


En pratique, il nest pas vraiment utile de connatre le nombre de secondes coules depuis le 1er janvier 1970, il est souvent commode de convertir cette valeur laide de la fonction localtime(). Elle renseigne une structure de type tm, quil est ensuite facile dafcher. Voici quel est son prototype :
struct tm *localtime(time_ptr *ptr);

Cette fonction renvoie donc un pointeur vers une structure statique de type tm. Il est donc inutile de dclarer une structure de ce type ; il suft de dclarer un pointeur vers un objet de type tm. Cest la mme structure statique qui est rutilise chaque appel de local time(), aussi, si vous voulez sauvegarder la valeur renvoye, vous devez dclarer une structure personnelle de type tm dans laquelle vous recopierez le rsultat de lappel localtime(). La conversion inverse (dune structure tm vers une valeur de type time t) saccomplit en appelant la fonction mktime() dont le prototype est :
time_t mktime(struct tm *ntime);

La fonction renvoie le nombre de secondes coules depuis le 1 er janvier 1970, et le temps reprsent par la structure de type tm pointe par ntime.

Afchage du temps
Pour convertir le temps en chanes de caractres pouvant tre afches, il existe deux fonctions : ctime() et asctime(). Les deux renvoient une chane de caractres dun format spcique. Elles diffrent par le type dargument qui doit leur tre pass :
char *asctime(struct tm *ptr); char *ctime(time_t *ptr);

http://fribok.blogspot.com/

Les deux fonctions renvoient un pointeur vers une chane de 26 caractres, statique, termine par un zro et de la forme :
Fri Sep 2206:43:461995

Notez que les abrviations des jours et des mois sont en anglais (ici, par exemple, Fri signie Friday, "vendredi"). Heureusement, lheure est compte " leuropenne", entre 0 et 23 heures. Pour mieux contrler le format du temps, on prfrera appeler la fonction strftime(), laquelle on passe une structure de type tm, et qui formate le temps selon une chane de caractres spciale. Son prototype est :
size_t strftime(char *s; size_t max, char *fmt, struct tm *ptr);

partir du temps reprsent par la structure pointe par ptr, la fonction formate les valeurs afcher selon les spcications de la chane pointe par fmt; puis elle crit le rsultat dans une chane de caractres termine par un zro lemplacement mmoire point par s. Si le rsultat (y compris le zro terminal) dpasse max caractres, la fonction renvoie 0 et le contenu de s est fauss. Sinon, elle renvoie le nombre de caractres rellement crits dans s, soit strlen(s). Les spcicateurs de format sont particuliers cette fonction. Le Tableau 19.1 en donne la liste.
Tableau 19.1 : Spcicateurs de format utiliser pour strftime()

Spcicateur %a %A %b %B %c %d %H %I %j

Remplac par
Nom du jour de la semaine en abrg Nom du jour de la semaine en entier Nom du mois en abrg Nom du mois en entier Date et heure (par exemple : 10:41:50. 30-Jun-_95) Jour du mois compris entre 1 et 31 Heure comprise entre 00 et 23 Heure comprise " lamricaine, AM et PM", entre 00 et 11 ( lamricaine, AM et PM) Le jour de lanne compris entre 001 et 366

http://fribok.blogspot.com/

Tableau 19.1 : Spcicateurs de format utiliser pour strftime() (suite)

Spcicateur %m %M %p %S %U %w %W %x %X %y %Y %Z %%

Remplac par
Le numro du mois compris entre 01 et 12 La nombre de minutes compris entre 00 et 59 Lune des deux chanes AM ou PM Le nombre de secondes compris entre 00 et 59 Le numro de la semaine de lanne compris entre 00 et 53. Dimanche est considr comme le premier jour de la semaine Le jour de la semaine compris entre 0 et 6 (dimanche = 0) Comme %U, mais, ici, cest lundi qui est considr comme le premier jour de la semaine La date reprsente sous forme "locale", par e. Exemples : 09/22/95 (Visual C++, version 2.0) ou Fri Sep 22, 1995 (Borland C++, version 4.02) Lheure, sous la forme HH:MM:SS Les deux derniers chiffres de lanne (par exemple : 95) Lanne "complte" (par exemple : 1995) Le nom de la zone horaire ou son abrviation, ou rien si elle ne peut pas tre dtermine (par exemple : EDT pour Borland ; rien pour Microsoft) Le caractre % lui-mme

Calcul dune diffrence de temps


La fonction difftime() permet de calculer la diffrence entre deux valeurs de type time t et renvoie leur diffrence. Son prototype est :
double difftime(time_later, time_earlier);

(Cest--dire, respectivement : "temps le plus rcent", "temps le plus ancien".) La fonction renvoie le nombre de secondes sparant les deux valeurs. Nous en verrons un exemple dans le programme du Listing 19.2. Vous pouvez dterminer la dure en tops dhorloge, cest--dire en intervalles de rsolution de lhorloge interne de votre ordinateur en appelant la fonction times() dont le prototype est :
clock_t times(struct tms *buf);

http://fribok.blogspot.com/

Il faut prendre une mesure au dbut du programme et faire la diffrence avec la mesure en n de programme. Le rsultat est exprim non pas en ticks mais en tops dhorloge. Le nombre de tops dhorloge par seconde sobtient avec sysconf( SC CLK TCK).

Utilisation des fonctions relatives au temps


Le programme du Listing 19.2 illustre la faon dutiliser les fonctions relatives au temps de la bibliothque standard. Listing 19.2 : Utilisation des fonctions de temps de la bibliothque standard
1:/* Exemples dutilisation des fonctions de temps. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <time.h> 5:#include <sys/times.h> 6:#include <unistd.h> 7: 8:int main() 9:{ 10:time_t start, finish, now; 11:struct tm *ptr; 12:char *c, buf1[80]; 13:double duration; 14:clock_t top_start, top_finish; 15:struct tms buf; 16: 17:/* Heure de dbut de lexcution. */ 18: 19:start = time(0); 20:top_start = times(&buf); 21: 22:/* Appel de ctime() pour enregistrer linstant de 23:dbut du programme. */ 24: 25:time(&now); 26: 27:/* Convertir la valeur time en une structure de type tm. */ 28: 29:ptr = localtime(&now); 30: 31:/* Crer et afficher une chane de caractres contenant 32:lheure actuelle. */ 33: 34:c = asctime(ptr); 35:puts(c); 36:getc(stdin); 37: 38:/* Utiliser maintenant la fonction strftime() pour crer 39:plusieurs versions formates du temps (date/heure) */ 40:strftime(buf1, 80, "Nous sommes dans la semaine \

http://fribok.blogspot.com/

Listing 19.2 : Utilisation des fonctions de temps de la bibliothque standard (suite)


41:%U de lanne%Y", ptr); 42:puts(buf1); 43:getc(stdin); 44: 45:strftime(buf1, 80, "Aujourdhui, nous sommes%A,%x", ptr); 46:puts(buf1); 47:getc(stdin); 48: 49:strftime(buf1, 80, "Il est%H heures et%M minutes.", ptr); 50:puts(buf1); 51:getc(stdin); 52: 53:/* Prenons lheure courante pour obtenir la dure 54:dexcution du programme. */ 55:finish = time(0); 56:top_finish = times(&buf); 57:duration = difftime(finish, start); 58: printf("\nDure dexcution du programme en utilisant \ 59:time() =%f secondes.",duration); 60:/* Affichons la mme dure, mais calcule avec times(). */ 61: 62:printf("\nDure dexcution du programme en utilisant \ 63:clock() =%ld centimes de seconde.", 64:100 * (top_finish - top_start)/sysconf(_SC_CLK_TCK)); 65: exit(EXIT_SUCCESS); 66:}

Rsultats obtenus avec le compilateur GCC 4.1.3 sur Linux (noyau 6.2) :
Thu Jan 1020:32:112008 Nous sommes dans la semaine 01 de lanne 2008 Aujourdhui, nous sommes Thursday, 01/10/08 Il est 20 heures et 32 minutes. Dure dexcution du programme en utilisant time() = 5.000000 secondes; Dure dexcution du programme en utilisant clock() = 5980 centimes de seconde.

Analyse Il y a beaucoup de lignes de commentaires dans ce programme, ce qui dispense les auteurs den rajouter ici. Linstant de dbut du programme est enregistr par lappel time() de la ligne 19. Ce qui va tre compt, ce nest pas le temps dexcution du programme proprement dit, mais les temps dattente occasionns par les getc() prsents aux lignes 36, 43, 47 et 51. Autrement dit, le temps de lecture de lcran par lutilisateur. On sera sans doute surpris de voir que le numro de semaine est 1 au lieu de 2. En fait, %U renvoie le numro de semaine dans un intervalle de 0 52. Il faut donc ajouter 1 pour avoir un nombre comparable celui du calendrier des Postes. Outre %U, il est aussi possible

http://fribok.blogspot.com/

dafcher le numro de semaine avec %V au format ISO 8601:1988 ou avec %W o la semaine 0 est celle du premier lundi de lanne.

Fonctions de traitement derreur


La bibliothque standard C contient un certain nombre de fonctions et de macros destines vous aider dans le traitement derreurs survenant lors de lexcution dun programme.

La fonction assert()
Cest en ralit une macro, dont le prototype se trouve dans le chier assert.h , et qui sert principalement mettre en vidence des bogues dans un programme :
void assert(int expression);

Largument expression peut tre nimporte quelle expression ou variable que vous souhaitez tester. Si le rsultat vaut vrai, assert() ne fait rien et on passe linstruction suivante. Si le rsultat vaut faux, assert() afche un message derreur sur stderr et le programme se termine. quelles ns utilise-t-on assert()? Essentiellement pour dceler des erreurs dans un programme au moment de son excution et non de sa compilation. Par exemple, supposez que vous ayez crit un programme danalyse nancire qui donne, de temps autre, des rponses incorrectes. Vous pensez que le problme peut provenir de la variable taux d interet prenant une valeur ngative (ce qui, nancirement, est dsastreux). Pour le vrier, il suft de placer "au bon endroit" linstruction :
assert(taux_d_interet >= 0);

Si jamais cette variable devient ngative, le programme se terminera aprs avoir afch un message derreur situant lendroit du programme o tait assert() et la condition teste. Le programme du Listing 19.3 permet de voir comment fonctionne cette macro. Si vous lui donnez une valeur non nulle, le programme afchera cette valeur et se terminera normalement. Sinon, il se terminera en erreur avec un message du type :
list19_3: list19_3.c:13: main: Assertion `x>0 failed.

Attention, vous ne pouvez utiliser cette macro que si votre programme a t compil en mode "dbogu". Vous trouverez comment activer ce mode en consultant la documentation de votre compilateur. Lorsque vous compilerez ensuite la version nale du programme corrig en mode normal, les macros assert() seront dsactives.

http://fribok.blogspot.com/

Listing 19.3 : Utilisation de la macro assert()


1:/* La macro assert(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <assert.h> 5: 6:int main() 7:{ 8:int x; 9: 10:printf("Tapez un nombre entier: "); 11:scanf("%d", &x); 12: 13:assert(x>0); 14: 15:printf("Vous avez tap:%d.\n", x); 16:exit(EXIT_SUCCESS); 17:}

Avec les compilateurs Turbo C de Borland et Visual C++ de Microsoft, on obtient les rsultats suivants :
C:\BC\DIVERS\List19_3 Tapez un nombre entier: 8 Vous avez tap: 8. C:\BC\DIVERS\list19_3 Tapez un nombre entier: 0 Assertion failed: x, file C:\BC\DIVERS\LIST19_3.C, line 13 abnormal program termination

Sur Linux avec le compilateur GCC, le rsultat est similaire :


$ list19_3 Tapez un nombre entier: 8 Vous avez tap: 8. $ list19_3 Tapez un nombre entier: 0 avirer: avirer3.c:13: main: Assertion `x>0 failed. Abandon

Ce message pourra tre diffrent selon le systme et le compilateur utiliss. Avec le compilateur Borland C++ 4.02, tournant sous Windows 95, lexcution seffectue dans une fentre MS-DOS. Mais une fois quon a tap 0, le premier message derreur apparat dans une fentre derreur superpose la fentre MS-DOS. Puis, ds quon a cliqu sur le bouton OK, la fentre est remplace par une autre, dans laquelle on lit : "Program Aborted".

http://fribok.blogspot.com/

Analyse Laction de assert() dpend dune constante symbolique appele NDEBUG. Si elle nest pas dnie (option par dfaut), assert() est active. Si on a crit :
#define NDEBUG #include <assert.h> .....

elle devient inactive. Il est donc simple de placer un peu partout des appels assert() et, une fois la mise au point darrt acheve, sans y toucher, de les dsactiver par le #define NDEBUG que nous venons de voir. Il est inutile de donner une valeur particulire la suite du #define. Nous verrons pourquoi au Chapitre 21.

Le chier den-tte errno.h


Le chier den-tte errno.h dnit plusieurs macros servant dnir et documenter les erreurs intervenant lexcution dun programme. Ces macros sont utilises en conjonction avec la fonction perror() que nous allons dcrire un peu plus loin. Dans errno.h, on trouve aussi la dclaration dune variable externe appele errno. Certaines fonctions de la bibliothque C peuvent lui assigner une valeur lorsquune erreur survient en cours dexcution. Nous avons dj rencontr cette variable au Chapitre 17 lorsquil sagissait de vrier la validit dun rsultat de la fonction strtol(). errno.h contient aussi un groupe de constantes symboliques correspondant ces erreurs. Le Tableau 19.2 en prsente quelques-unes.
Tableau 19.2 : Quelques-unes des constantes symboliques dnies dans errno.h

Nom E2BIG EACCESS EBADF EDOM EEXIST EMFILE ENOENT

Valeur
20 5 6 33 35 4 2

Message et signication
Liste darguments trop longue (> 128 octets) Permission refuse (par exemple, aprs une tentative dcriture sur un chier ouvert en lecture seule) Mauvais descripteur de chier Argument mathmatique en dehors du domaine autoris Le chier existe dj Trop de chiers ouverts Fichier ou rpertoire inexistant

http://fribok.blogspot.com/

Tableau 19.2 : Quelques-unes des constantes symboliques dnies dans errno.h (suite)

Nom ENOEXEC ENOMEM ENOPATH ERANGE

Valeur
21 8 3 34

Message et signication
Erreur sur le format dexcution Mmoire sufsante Chemin daccs non trouv Rsultat en dehors des limites

Il y a deux faons dutiliser errno. Certaines fonctions signalent, au moyen de leur valeur de retour, quune erreur vient de se produire. Dans ce cas, vous pouvez tester la valeur de errno pour dterminer la nature de lerreur et excuter telle ou telle action. Sinon, lorsque rien ne vient spontanment vous signaler quune erreur a eu lieu, testez errno. Si sa valeur nest pas nulle, cest quune erreur est survenue et cette valeur indique la nature de lerreur. Noubliez pas de remettre errno zro aprs avoir trait lerreur. Lorsque nous aurons tudi perror(), vous pourrez voir sur le Listing 19.4 un exemple dutilisation derrno.

La fonction perror()
La fonction perror() est un autre spcimen des outils que C propose pour le traitement des erreurs. Lorsquelle est appele, cette fonction envoie sur stderr un message dcrivant la plus rcente erreur survenue pendant lappel dune fonction de la bibliothque ou dune fonction systme. Si vous appelez perror() en labsence de toute erreur, le message sera no error. Un appel perror() neffectue aucun traitement de lerreur, la fonction se contentant denvoyer un message. Cest au programme de dcider de laction entreprendre. Celleci peut consister demander lutilisateur darrter le programme. Il nest pas ncessaire que le programme contienne un #include <errno.h> pour pouvoir utiliser errno. Ce chier den-tte nest indispensable que si vous voulez utiliser les constantes symboliques gurant dans le Tableau 19.2. Le Listing 19.4 montre lutilisation de la fonction perror() et de errno pour le traitement des erreurs dexcution. Listing 19.4 : Utilisation de perror() et de errno pour traiter les erreurs survenant lexcution
1:/* Exemple de traitement derreur avec perror()et errno. */ 2: 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <errno.h> 6:

http://fribok.blogspot.com/

7:int main() 8:{ 9:FILE *fp; 10:char filename[80]; 11: 12:printf("Indiquez un nom de fichier: "); 13:lire_clavier(filename, sizeof(filename)); 14: 15:if ((fp = fopen(filename, "r")) == NULL) 16:{ 17:perror("Vous vous tes tromp!"); 18:printf("errno =%d.\n", errno); 19:exit(EXIT_FAILURE); 20:} 21:else 22:{ 23:puts("Fichier ouvert en lecture."); 24:fclose(fp); 25:} 26:exit(EXIT_SUCCESS); 27:} Indiquez un nom de fichier: toto Fichier ouvert en lecture. Indiquez un nom de fichier: zozor Vous vous tes tromp!: No such file or directory errno = 2.

Dans les pays anglo-saxons, leffet est, sans doute, assez russi. Dans notre pays, ce mlange de langues fait un peu dsordre. Analyse Le programme peut afcher deux messages, selon le chier quon veut ouvrir. Si on peut louvrir en lecture, tout va bien ; sinon (chier inexistant), on afche un message derreur compos dune partie sur mesure ("Vous vous tes tromp") laquelle perror() concatne son propre message (": no such le or directory"). faire Inclure le chier den-tte errno.h si vous avez lintention dutiliser les constantes symboliques derreur dont quelques-unes sont listes au Tableau 19.2. Rechercher dventuelles erreurs dans le programme. Ne supposez jamais que tout va pour le mieux dans le meilleur des mondes.

eils Cons

http://fribok.blogspot.com/

ne pas faire Inclure le chier den-tte errno.h si vous navez pas lintention dutiliser les constantes symboliques derreur. Utiliser la valeur des constantes du Tableau 19.2. Si vous avez besoin de tester errno, comparez-le aux constantes symboliques.

Recherche et tri
Parmi les tches les plus courantes quun programme peut avoir accomplir, on trouve la recherche (consultation de table ou de liste) et le tri. La bibliothque standard du C contient des fonctions dusage gnral pour ces deux tches.

Recherche avec bsearch()


La fonction de bibliothque bsearch() (de langlais Binary SEARCH) accomplit une recherche dichotomique dans un tableau dobjets an dy trouver une correspondance avec une cl de recherche donne. Le tableau doit tre pralablement tri en ordre croissant. Le programme doit fournir une fonction de comparaison capable de renvoyer un entier ngatif, positif ou nul, selon que le rsultat de la comparaison avec la cl de recherche est infrieur, gal ou suprieur. Son prototype se trouve dans stdlib.h :
void *bsearch(void *key, void *base, size_t num, size_t width, int (*cmp)(void *element1, void *element2));

Ce prototype plutt complexe mrite dtre tudi minutieusement :


key est un pointeur vers largument de recherche (la cl). base est un pointeur vers le premier lment du tableau de recherche. num est le nombre dlments du tableau. width est la taille dun lment. cmp est un pointeur vers la fonction de comparaison.

Les deux premiers pointeurs sont de type void. Cela permet de faire une recherche dans un tableau contenant nimporte quel type dobjets. num et width sont de type size t, car leur valeur est gnralement obtenue par un appel loprateur sizeof().

http://fribok.blogspot.com/

La fonction cmp est gnralement une fonction crite par lutilisateur. Si la recherche seffectue sur des chanes de caractres, on utilise la fonction de bibliothque standard strcmp(). Elle doit rpondre au cahier des charges suivant :

Elle reoit en argument deux pointeurs, un sur chacun des objets comparer. Elle renvoie un entier : ngatif si element1 < element2;. nul si element1 = element2;. positif si element1 > element2..

La valeur de retour de bsearch() est un pointeur de type void vers le premier lment du tableau qui soit gal la cl de recherche. Sil ny a pas de correspondance, on obtient NULL. Lalgorithme de recherche dichotomique est trs efcace. Nous avons vu quil exigeait que le tableau soit pralablement tri en ordre ascendant. Voici comment il opre : 1. La cl est compare llment situ au milieu du tableau. Selon le signe du rsultat de la comparaison, on sait que la cl se trouve en dessous ou au-dessus du point de correspondance. Si la fonction de comparaison renvoie zro, cet lment constitue la rponse cherche. 2. La recherche se poursuit dans lune des deux moitis qui est, son tour, divise en deux. 3. Et ainsi de suite jusqu ce quon ait trouv une correspondance, ou quil ne reste plus dlments. Cette mthode limine chaque coup une moiti du tableau restant. Dans un tableau de mille lments, on trouvera le rsultat en dix comparaisons, au plus. En gnral, pour un tableau de 2n lments, il faut n comparaisons.

Tri avec qsort()


La fonction de bibliothque standard qsort() est une implmentation de lalgorithme de tri quicksort, invent par C. A. R. Hoare. Le tableau est gnralement tri en ordre croissant, mais il est possible de le trier en ordre dcroissant. Le prototype de la fonction (qui est dnie dans stdlib.h) est le suivant :
void qsort(void *base, size_t num, size_t size, int (*cmp)(void *element1, void *element2));

http://fribok.blogspot.com/

Largument base pointe sur le premier lment du tableau de num lments dune taille de size octets chacun ; cmp est un pointeur vers une fonction de comparaison analogue celle utilise pour bsearch(). La fonction qsort() ne renvoie aucune valeur.

Recherche et tri : deux exemples


Le programme du Listing 19.5 montre lutilisation de qsort() et bsearch(). Vous noterez la prsence, dans le programme, de la fonction getc() destine permettre de voir ce qui se passe en arrtant temporairement lexcution du programme. Listing 19.5 : Utilisation de qsort() et bsearch() pour trier des valeurs
1:/* Utilisation de qsort()et de bsearch() avec des valeurs.*/ 2: 3:#include <stdio.h> 4:#include <stdlib.h> 5: 6:#define MAX 20 7: 8:int intcmp(const void *v1, const void *v2); 9: 10:int main() 11:{ 12:int arr[MAX], count, key, *ptr; 13: 14:/* Lutilisateur va taper quelques nombres entiers. */ 15: 16:printf("Tapez%d valeurs entires spares par un \ 17:appui sur Entre.\n", MAX); 18:for (count = 0; count < MAX; count++) 19:scanf("%d", &arr[count]); 20: 21:puts("Appuyez sur Entre pour effectuer le tri."); 22:getc(stdin); 23: 24:/* Trier le tableau en ordre croissant. */ 25: 26:qsort(arr, MAX, sizeof(arr[0]), intcmp); 27: 28:/* Afficher le tableau tri. */ 29: 30:for (count = 0; count < MAX; count++) 31:printf("\narr[%d] =%d.", count, arr[count]); 32: 33:puts("\nAppuyez sur Entre pour continuer."); 34:getc(stdin); 35: 36:/* Entre dune cl de recherche. */ 37: 38:printf("Tapez la valeur rechercher: "); 39:scanf("%d", &key); 40:

http://fribok.blogspot.com/

41:/* Effectuer la recherche. */ 42: 43:ptr = (int *)bsearch(&key, arr, MAX, sizeof(arr[0]),intcmp); 44: 45:if (ptr!= NULL) 46:printf("%d trouv arr[%d].", key, (ptr arr)); 47:else 48:printf("%d non trouv.", key); 49:exit(EXIT_SUCCESS); 50:} 51: 52:int intcmp(const void *v1, const void *v2) 53:{ 54:return (*(int *)v1 *(int *)v2); 55:} Tapez 20 valeurs entires spares par un appui sur Entre. 45 12 999 1000 321 123 2300 954 1968 12 2 1999 3261 1812 743 1 10000 3 76 329 Appuyez sur Entre pour effectuer le tri. arr[0] = 1. arr[1] = 2. arr[2] = 3. arr[3] = 12. arr[4] = 12. arr[5] = 45. arr[6] = 76. arr[7] = 123. arr[8] = 321. arr[9] = 329. arr[10] = 743. arr[11] = 954. arr[12] = 999. arr[13] = 1000. arr[14] = 1812. arr[15] = 1968.

http://fribok.blogspot.com/

arr[16] arr[17] arr[18] arr[19] Appuyez

= 1999. = 2300. = 3261. = 10000. sur Entre pour continuer.

Tapez la valeur rechercher: 1812 1812 trouv arr[14].

Analyse Le programme commence par vous demander de taper un nombre MAX de valeurs (ici, 20). Il les trie en ordre croissant et les afche dans cet ordre. Ensuite, il vous demande une valeur de recherche et afche le rang de llment o il la trouve ou "non trouve". La logique du programme est absolument squentielle, ce qui fait quavec les explications donnes plus haut, tout commentaire serait redondant. Le Listing 19.6 illustre lemploi de ces fonctions, cette fois sur des chanes de caractres. Listing19.6 : Utilisation de qsort() et bsearch() pour trier des chanes de caractres
1:/* Utilisation de qsort()et de bsearch() sur des chanes de 2:caractres. */ 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <string.h> 6: 7:#define MAX 20 8: 9:int comp(const void *s1, const void *s2); 10: 11:int main() 12:{ 13:char *data[MAX], buf[80], *ptr, *key, **key1; 14:int count; 15: 16:/* Entre dune suite de mots. */ 17: 18:printf("Tapez%d mots spars par un appui sur \ 19:Entre.\n", MAX); 20:for (count = 0; count < MAX; count++) 21:{ 22:printf("Mot%d: ", count+1); 23:lire_clavier(buf, sizeof(buf)); 24:data[count] = strdup(buf); 25:} 26: 27:/* Trier les mots (en ralit, les pointeurs). */ 28: 29:qsort(data, MAX, sizeof(data[0]), comp);

http://fribok.blogspot.com/

30: 31:/* Afficher les mots tris. */ 32: 33:for (count = 0; count < MAX; count++) 34:printf("\n%d:%s", count+1, data[count]); 35: 36:/* Demander une cl de recherche. */ 37: 38:printf("\n\nTapez une cl de recherche: "); 49:lire_clavier(buf, sizeof(buf)); 40: 41:/* Effectuer la recherche. Commencer par dfinir key1 comme 42:un pointeur vers le pointeur sur la cl de recherche */ 43: 44:key = buf; 45:key1 = &key; 46:ptr = bsearch(key1, data, MAX, sizeof(data[0]), comp); 47: 48:if (ptr!= NULL) 49:printf("%s trouv.\n", buf); 50:else 51:printf("%s non trouv.\n", buf); 52:exit(EXIT_SUCCESS); 53:} 54: 55:int comp(const void *s1, const void *s2) 56:{ 57:return (strcmp(*(char **)s1, *(char **)s2)); 58:} Tapez 20 mots spars par un appui sur Entre. Mot 1:abricot Mot 2:amande Mot 3:ananas Mot 4:banane Mot 5:brugnon Mot 6:chou Mot 7:concombre Mot 8:courgette Mot 9:framboise Mot 10: groseille Mot 11: laitue Mot 12: mre Mot 13: orange Mot 14: oseille Mot 15: poire Mot 16: pomme Mot 17: pomme Mot 18: potiron Mot 19: pche Mot 20: raisin

http://fribok.blogspot.com/

1:abricot 2:amande 3:ananas 4:banane 5:brugnon 6:chou 7:concombre 8:courgette 9:framboise 10: groseille 11: laitue 12: mre 13: orange 14: oseille 15: poire 16: pomme 17: pomme 18: potiron 19: pche 20: raisin Tapez une cl de recherche: potiron potiron trouv.

Analyse Lorganisation gnrale du programme est identique celle du prcdent, quelques dtails prs. On fait ici usage dun tableau de pointeurs vers les chanes de caractres, technique qui vous a t prsente au Chapitre 15. Comme nous lavons vu, on peut trier des chanes en ne triant que leurs pointeurs. Il faut, pour cela, modier la fonction de comparaison. On lui passera un pointeur vers chacun des pointeurs des lments du tableau comparer. Faute de quoi, ce seraient les pointeurs qui seraient tris et non les lments sur lesquels ils pointent. lintrieur de la fonction, il est alors ncessaire de "drfrencer" les pointeurs pour atteindre chaque lment. Cest la raison du double astrisque de la ligne 57. La cl de recherche a t place en buf[] et on sait que le nom dun tableau (ici, buf) est un pointeur vers le tableau. Mais ce quon veut passer, ce nest pas buf lui-mme, mais un pointeur vers buf. Seulement, buf est une constante pointeur, et non une variable pointeur, et na donc pas dadresse en mmoire. Cest pourquoi on ne peut pas crer un pointeur qui pointe vers buf au moyen de loprateur adresse devant buf en crivant &buf. Que peut-on faire ? Dabord, crer une variable pointeur et lui assigner la valeur de buf (ligne 45). Dans le programme, elle sappelle key. Comme key est une variable, elle a une adresse et vous pouvez crer un pointeur contenant cette adresse. Nous lappellerons key1 (ligne 46).

http://fribok.blogspot.com/

Lors de lappel de bsearch(), le premier argument est key1, qui est un pointeur vers un pointeur vers la chane de caractres qui est la cl. (Ouf !)
eils Cons

ne pas faire Oublier de trier votre tableau en ordre croissant avant dappeler bsearch(). Oublier de librer la mmoire alloue (ici avec avec strdup()).

Rsum
Dans ce chapitre, nous avons explor quelques-unes des fonctions les plus utiles de la bibliothque standard du C. Certaines font des calculs mathmatiques, dautres traitent du temps, dautres encore vous assistent dans la mise au point de vos programmes et le traitement des erreurs. Les fonctions de tri et de recherche sont particulirement utiles, car elles permettent dconomiser beaucoup de temps lors de lcriture de vos programmes. Sachez quil existe par ailleurs des bibliothques de fonctions qui implmentent des structures de donnes plus adaptes la recherche ou au tri des donnes. Si vous devez utiliser une table de hachage ou un arbre binaire balanc, ne rinventez pas la roue.

Q&R
Q Pourquoi est-ce que la plupart des fonctions mathmatiques renvoient un double ? R Pour une question de prcision, car on obtient ainsi davantage de chiffres signicatifs et un exposant plus tendu quavec de simples oat. Q Est-ce que bsearch() et qsort() sont les seules faons de chercher et de trier en C ? R Bien sr que non. Elles gurent dans la bibliothque standard pour votre commodit, mais vous ntes pas oblig de les utiliser. Dans beaucoup de livres sur le C vous trouverez des algorithmes de tri et de recherche et les programmes qui vont avec. Ces fonctions sont dailleurs dj implmentes dans des bibliothques non standard. Certaines sont nanmoins assez rpandues (comme glib sur Linux, Windows, MacOS X...) pour que vous puissiez les utiliser tout en garantissant votre programme une certaine portabilit. Le plus grand intrt des fonctions bsearch() et qsort() est quelles sont dj prtes et quelles sont fournies avec tous les compilateurs ANSI. Q Est-ce que les fonctions mathmatiques vrient les arguments qui leur sont passs ? R Absolument pas. Cest vous de le faire. Si, par exemple, vous passez une valeur ngative sqrt(), vous obtiendrez une erreur.

http://fribok.blogspot.com/

Atelier
Latelier vous propose quelques questions permettant de tester vos connaissances sur les sujets que nous venons daborder dans ce chapitre.

Quiz
1. Quel est le type de la valeur renvoye par quasi toutes les fonctions mathmatiques ? 2. quel type de variable C le type time t est-il quivalent ? 3. Quelles sont les diffrences entre les fonctions time(), times() et clock()? 4. Lorsque vous appelez la fonction perror(), que fait-elle pour corriger une condition derreur ? 5. Avant de pratiquer une recherche dans un tableau avec bsearch(), que devez-vous faire ? 6. Avec bsearch(), combien de comparaisons vous faudra-t-il, au plus, pour trouver une correspondance dans un tableau de 16 000 articles ? 7. Avec bsearch(), combien de comparaisons vous faudra-t-il, au plus, pour trouver une correspondance dans un tableau de 10 articles ? 8. Avec bsearch(), combien de comparaisons vous faudra-t-il, au plus, pour trouver une correspondance dans un tableau de 2 millions darticles ? 9. Quelle valeur doit renvoyer la fonction de comparaison gurant en argument de bsearch() et qsort()? 10. Que renvoie bsearch() si elle ne trouve pas de correspondant dans le tableau ?

Exercices
1. crivez un appel bsearch(). Le tableau dans lequel seffectuera la recherche sappelle names et contient des chanes de caractres. La fonction de comparaison sappelle comp names(). On supposera que tous les noms ont la mme longueur. 2. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions qui suivent ?
#include <stdio.h> #include <stdlib.h> int main() { int value[10], count, key, *ptr; printf("Tapez des valeurs:"); for (ctr=0; ctr<10; ctr++) scanf("%d", &values[ctr]);

http://fribok.blogspot.com/

qsort(values, 10, compare_function()); exit(EXIT_SUCCESS); }

3. CHERCHEZ LERREUR : Y a-t-il quelque chose de faux dans les instructions qui suivent ?
int intcmp(int element_1, int element_2) { if (element_1 > element_2) return 1; if (element_1 < element_2) return 1; return 0; }

On ne donne pas les corrigs des exercices suivants. 4. Modiez le programme du Listing 19.1 pour que la fonction sqrt() puisse travailler sur la valeur absolue des nombres ngatifs. 5. crivez un programme qui consiste en un menu vous proposant plusieurs fonctions mathmatiques. Mettez-y autant de fonctions que vous pourrez. 6. crivez une fonction qui arrte le programme pendant environ 5 secondes, en utilisant les fonctions de traitement du temps que nous avons vues dans ce chapitre. 7. Ajoutez la fonction assert() au programme de lexercice 4 de faon ce quil puisse afcher un message lorsque lutilisateur tape un nombre ngatif. 8. crivez un programme qui lit 30 noms taps par lutilisateur et les trie avec qsort(). Il devra afcher les noms une fois tris. 9. Modiez le programme de lexercice 8 pour que, si lutilisateur tape "quit", le programme cesse de demander des noms et se mette trier ceux quil a dj reus. 10. Au Chapitre 15, vous avez vu une mthode de tri lmentaire dont nous vous avons signal la lenteur. Faites-lui trier un grand tableau puis comparez le temps quelle a mis pour le faire au temps mis par la fonction de bibliothque qsort() pour trier le mme tableau.

http://fribok.blogspot.com/

Exemple pratique 6

Calcul des versements dun prt


Le programme prsent dans cette section est destin au calcul des remboursements dun emprunt. En lexcutant, vous devrez lui transmettre trois informations :

Le montant de lemprunt (ou principal). Le taux dintrt annuel. Vous devez indiquer le taux rel ; par exemple, 8,5 pour 8,5 %. Ne calculez pas la valeur numrique relle (0,085 dans notre cas) puisque le programme sen charge. Le nombre de mensualits pour le remboursement.

Ce programme vous permettra de calculer le tableau damortissement dun prt immobilier ou de tout autre type demprunt. Listing Exemple pratique 6 : Calcul du montant des remboursements dun prt
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: /* Calcul des mensualits dun emprunt. */ #include <stdio.h> #include <math.h> #include <stdlib.h> int main() { float principal, rate, payment; int term; char ch; while (1) {

http://fribok.blogspot.com/

15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: }

/* Lecture des donnes concernant lemprunt */ puts("\nEntrez le montant de lemprunt: "); scanf("%f", &principal); puts("\nEntrez le taux dintrt annuel: "); scanf("%f", &rate); /* Ajustement du pourcentage. */ rate /= 100; /* Calcul du taux dintrt mensuel. */ rate /= 12; puts("\nEntrez la dure de remboursement du prt en mois: "); scanf("%d", &term); payment = (principal * rate) / (1 - pow((1+rate), -term)); printf("Vos mensualits se monteront $%.2f.\n", payment); puts("Autre calcul (o ou n)?"); do { ch = getchar(); } while (ch!= n && ch!= o); if (ch == n) break; } exit(EXIT_SUCCESS);

Analyse Ce programme de calcul est prvu pour un prt standard comme le nancement dune voiture taux xe ou un emprunt immobilier. Les remboursements sont calculs laide de la formule nancire suivante :
paiement = (P * R) / (1 - (1+R)^(-T))

P est le principal, R le taux dintrt, et T la priode. Le symbole ^ signie " la puissance". Dans cette formule, il est important dexprimer la priode et le taux avec la mme unit de temps. Si la dure de lemprunt est indique en mois, par exemple, le taux dintrt devra aussi tre le taux mensuel. Les taux dintrts tant gnralement exprims en taux annuels, la ligne 23 divise ce taux par 12 pour obtenir le taux mensuel correspondant. Le calcul des chances seffectue en ligne 27 et la ligne 28 afche les rsultats.

http://fribok.blogspot.com/

20
La mmoire
Ce chapitre traite quelques aspects parmi les plus avancs de la gestion de mmoire dans les programmes C :

Conversions de types Allocation et libration de mmoire Manipulations sur des blocs de mmoire Manipulations des bits

http://fribok.blogspot.com/

Conversions de types
Tous les objets C ont un type dni. Une variable numrique peut tre un int ou un float, un pointeur peut pointer vers un double ou un char, et ainsi de suite. Dans les programmes, on a souvent besoin de mlanger diffrents types dans une mme expression. Quarrive-t-il alors ? Parfois, C se charge automatiquement des conversions ncessaires ; dautres moments, cest vous deffectuer ces conversions pour viter dobtenir des rsultats errons. Vous en avez vu des exemples dans les chapitres prcdents, et nous avons mme tudi le casting ncessaire dun pointeur de type void vers un type spcique de donnes. Dans ce cas et dans les autres, vous devez comprendre ce qui se passe pour tre mme de dcider sil faut ou non effectuer une conversion explicite et dvaluer les risques derreur si vous nen faisiez pas.

Conversions automatiques de types


Comme leur nom lindique, ce sont des conversions effectues automatiquement par le compilateur C, sans que vous ayez intervenir. Pour juger de leur bien fond, vous devez comprendre comment C value les expressions.

Promotion de type dans une expression


Lorsquune expression C est value, la valeur qui en rsulte est dun type particulier. Si tous les constituants de lexpression sont du mme type, le rsultat est lui-mme de ce type. Par exemple, si x et y sont des int, le rsultat de lvaluation de lexpression suivante est aussi du type int:
x+y

Que va-t-il se passer si lune des variables nest pas du mme type ? Dans ce cas, le compilateur va "sarranger" pour viter une perte dinformations en allant du plus "pauvre" vers le plus "riche" dans la liste suivante : char, int, long, float et double. Donc, si, dans lexpression, y tait un char, le rsultat serait du type int. Si on associe un long et un float dans une expression, le rsultat sera de type float. lintrieur dune expression, les oprandes individuels sont promus, si cest ncessaire, pour correspondre aux oprandes de lexpression auxquels ils sont associs. Les oprandes subissent cette promotion par paires, pour chaque oprateur binaire. Bien entendu, si deux oprandes sont de mme type, aucune promotion nest ncessaire. Voici les rgles suivies, dans cet ordre, par ce mcanisme de promotion :

Si lun des oprandes est un double, lautre oprande est promu au type double.

http://fribok.blogspot.com/

Si lun des oprandes est un float, lautre oprande est promu au type float. Si lun des oprandes est un long, lautre oprande est promu au type long.

Si, par exemple, x est un int et y un float, lvaluation de lexpression x / y entranera la promotion de x en float avant que ne soit effectue la division. Cela ne signie pas que le type de x a t chang mais, tout simplement, quune copie de x a t convertie en float avant deffectuer la division. Le rsultat de celle-ci est naturellement de type float. De la mme faon, si x est un double et y un float, y sera promu en double.

Conversion par affectation


Les promotions interviennent de chaque ct du signe (=). Une fois value, lexpression de droite est toujours promue au type de la L Value de gauche. Notez que cette opration peut aboutir une "dgradation" du rsultat, cest--dire sa conversion dans un type plus pauvre. Si, par exemple, f est de type float et i de type int, le rsultat de lvaluation de lexpression i (cest--dire i lui-mme) sera promu au type float dans lexpression :
f = i;

Au contraire, si on avait crit :


i = f;

cest f qui aurait t converti en int par lablation de sa partie dcimale. Rappelez-vous que cela ne change en rien la valeur de f puisque cela ne concerne que la copie de f utilise dans laffectation. Aprs avoir excut les trois instructions suivantes :
float f=1.23; int i; i = f;3

i a la valeur 1 et f vaut toujours 1.23. Lorsquun float est dgrad en int, il subit gnralement des pertes alors que, dans lautre sens, ce nest pas souvent le cas. En effet, un entier peut toujours tre dcompos en une somme de puissances entires de 2 (base de reprsentation interne dans les machines modernes). Ainsi, dans les instructions suivantes :
float f; int i = 3; f = i; printf("%f\n", f);

http://fribok.blogspot.com/

on afchera bien 3. (et non 2.999995). En revanche, ds quon opre avec des nombres fractionnaires, les erreurs darrondis se cumulent gnralement, comme on peut en juger dans lexemple suivant :
#include <stdio.h> int main() { float a=.001, b=0; int i; for (i=0; i<1000; i++) b +=a; printf("la somme vaut%8.6f\n", b); }

Le rsultat obtenu ne vaut pas 1, mais 0,999991. On aurait eu dautres surprises si i avait t de type long, comme le montre lexemple suivant :
float f; long i =987654321; f = i; printf("%f\n", f);

o on afchera comme valeur de f: 987654336.000000. L, lerreur provient du fait que le nombre de chiffres signicatifs dun float est plus petit que celui dun long.

Conversions explicites avec coercition


Nous avons dj rencontr le casting. La dernire fois, ctait au Chapitre 18 o nous avons dit quon pouvait traduire ce mot par "coercition". Nous emploierons indiffremment les deux termes, le premier tant prfr par les programmeurs, le second par ceux qui sattachent la puret de leur langue. Quoi quil en soit, nous disposons l du moyen deffectuer une conversion explicite dun type dans un autre. Loprateur de coercition scrit en plaant le type du rsultat obtenir entre parenthses, devant la variable ou lexpression (entre parenthses, elle aussi, dans ce cas) forcer.

Coercition dans les expressions arithmtiques


La coercition oblige le compilateur effectuer une conversion de type, mme (et surtout) sil ntait pas dcid le faire implicitement. Par exemple, si i est de type int, crire
(float)i

http://fribok.blogspot.com/

transforme la copie interne de i en float (toujours sans changer ce qui se trouve dans la variable i). quel moment doit-on faire usage de la coercition ? Souvent pour viter toute perte de prcision dans une division, comme on peut le voir dans le programme du Listing 20.1. Listing 20.1 : Exemple simple dutilisation de la coercition
1:#include <stdio.h> 2:#include <stdlib.h> 3:int main() 4:{ 5:int i1 = 100, i2 = 40; 6:float f1, f2; 7: 8:f1 = i1 / i2; 9:f2 = (float)i1 / i2; 10: printf("Sans coercition:%f Avec coercition:%f\n", f1, f2); 11: exit(EXIT_SUCCESS); 12:} Sans coercition: 2.000000 Avec coercition: 2.500000

Analyse On voit que le premier rsultat est grossirement erron. En effet, le rsultat de la division de deux entiers (ligne 8) est un entier ; donc 100/40 donne 2. Si, en revanche, on emploie la coercition sur lun des deux oprandes de la division, comme la ligne 9, il y a conversion implicite de lautre terme et la division seffectue entre deux nombres de type float. Le rsultat rang dans f2 est donc un float. Notez que, si on avait crit :
f2 = (float)(i1 / i2);

on aurait encore obtenu 2.000000, car cest le quotient qui aurait subi la coercition, la division ayant t effectue entre deux int. Mais on aurait pu, aussi bien, user de coercition pour chacun des deux oprandes, plutt que de laisser faire le compilateur pour lautre terme, en crivant :
f2 = (float)i1 / (float) i2;

Ici, on aurait obtenu 2.500000, valeur correcte.

http://fribok.blogspot.com/

La coercition applique aux pointeurs


Au Chapitre 18, nous avons eu loccasion de rencontrer la coercition applique aux pointeurs. Un pointeur de type void est un pointeur gnrique ne pouvant pointer sur aucun type dobjet dni. Il est donc ncessaire de le caster pour pouvoir lutiliser. Notez quil nest pas ncessaire de le caster pour lui assigner une valeur (une adresse), pas plus que pour le comparer NULL. Cependant, vous devez le caster avant de lutiliser pour rfrencer une variable ou de le faire intervenir dans une opration arithmtique daddition ou de soustraction (du type p++, par exemple).
eils Cons

faire Utiliser un casting pour promouvoir ou dgrader une variable, lorsque cest ncessaire. ne pas faire Utiliser une promotion rien que pour viter un diagnostic du compilateur. Il faut dabord bien comprendre la signication de ce diagnostic et voir sil na pas une autre cause.

Allocation despace mmoire


La bibliothque C contient des fonctions dallocation de mmoire dynamique, cest--dire dallocation de mmoire au moment de lexcution. Cette technique peut avoir de gros avantages par rapport la rservation automatique et systmatique effectue au moment de la compilation, quon appelle allocation statique. Cette dernire demande que les dimensions maximales des tableaux ou structures soient connues au moment de lcriture du programme, alors que lallocation dynamique permet de se limiter la mmoire strictement ncessaire au cas particulier quon traite. Les fonctions utiliser ont leur prototype dans stdlib.h. Toutes les fonctions dallocation renvoient un pointeur de type void. (Sauf free(), mais ce nest pas, stricto sensu, une fonction dallocation puisque, au contraire, cest elle qui permet de restituer la mmoire acquise dynamiquement.) Contrairement au langage C++ il ne faut pas caster ce pointeur lors de lappel une fonction dallocation. Cest une erreur courante en C qui provient des premires version du langage C et des livres qui se basent dessus sans tenir compte de la norme C89 ; cette erreur est entretenue par la ncessit de caster en C++. Avant dentrer dans les dtails, arrtons-nous sur la signication physique de cette opration concernant la mmoire dont dispose lordinateur (mmoire RAM qui est variable selon la conguration installe). Lorsquon excute un programme quel quil soit (un traitement de texte ou un programme crit par soi-mme dans un langage quelconque), il est

http://fribok.blogspot.com/

charg partir du disque dans la mmoire de lordinateur. Outre les instructions du programme (et celles des fonctions de la bibliothque rajoutes au moment de ldition de liens), on a besoin de place pour loger les variables statiques, cest--dire celles qui ont t dclares dans le programme. Or, une partie de la mmoire est dj occupe par diverses composantes du systme dexploitation. On ne peut donc gnralement pas savoir sil restera assez de place, surtout quand on utilise de grands tableaux. La mmoire est une denre qui, si elle nest plus chre et rare comme au temps de MS-DOS, reste prcieuse. Cela se sent en particulier pour les excutables mal programms, o la mmoire nest pas systmatiquement libre lorsquelle nest plus ncessaire : ces excutables se mettent alors consommer de plus en plus de mmoire, ce qui peut ralentir lordinateur de manire signicative. Par ailleurs, si les fonctions dallocation fonctionnent gnralement bien, en vous renvoyant un pointeur vers la zone alloue, vous devez systmatiquement tester ce pointeur. Sil est NULL, lallocation a chou. Lorsque cela arrive, vous pouvez gnralement mettre n votre programme en afchant un message derreur (avec perror() par exemple) et en quittant avec exit(EXIT FAILURE). Sans mmoire, point de salut !

La fonction malloc()
Au cours des chapitres prcdents, vous avez appris utiliser la fonction malloc() pour allouer lespace ncessaire des chanes de caractres. Son utilisation nest pas limite ce type dobjet ; elle est capable dallouer de la mmoire pour tout objet C. Rappelons que son prototype est :
void *malloc(size_t num);

Largument size t est dni dans stdlib.h comme un unsigned. La fonction renvoie un pointeur sur le premier octet du bloc dune longueur de num octets, ou NULL sil ne reste plus assez de mmoire disponible (ou si num vaut 0). Le programme du Listing 20.2 vous montre comment utiliser malloc() correctement avec un test vriant que la mmoire a t alloue, et avec un appel free() pour librer la mmoire. Nous verrons free() plus loin. Listing 20.2 : Utilisation classique de malloc()
1:/* Utilisation classique de malloc().*/ 2:#include <stdio.h> 3:#include <stdlib.h> 4: 5:/* Dfinition dune structure ayant 6:une taille de l024 octets (l Koctet). */ 7: 8:struct kilo

http://fribok.blogspot.com/

Listing 20.2 : Utilisation classique de malloc() (suite)


9:{ 10:char dummy[1024]; 11:}; 12: 13:int main()14:{ 15:struct kilo un_kilo; 16: 17:if(NULL == (un_kilo = malloc(sizeof(*un_kilo)))) 18:{ 19:perror("Problme dallocation mmoire "); 20:exit(EXIT_FAILURE); 21:} 22:/* La mmoire est alloue. 23:On peut utiliser un_kilo ici. 24:*/ 25: 26:free(un_kilo); 27: 28: exit(EXIT_SUCCESS); 29:}

Analyse Ce programme alloue de la mmoire ligne 17. Vous remarquerez plusieurs points sur cette faon dallouer la mmoire. Tout dabord, la taille de la zone allouer est sizeof(*un kilo), soit la taille du type point par le pointeur, soit encore la taille dun struct kilo dans notre cas. En indiquant la taille de cette faon, vous pouvez modier le type de votre variable. La ligne 17 ne changera pas et correspondra toujours la bonne taille allouer. Vous noterez galement quun test est effectu sur cette mme ligne. Cela peut sembler nuire la lisibilit. En ralit, ce nest quune question dhabitude visuelle. Par contre, cest galement une excellente habitude car en encapsulant lallocation mmoire dans ce test, vous ne pouvez oublier deffectuer ce test ! Si lallocation mmoire choue, il est inutile de continuer le programme. Il prend n aprs avoir afch un message derreur lignes 19 et 20. Sinon, on peut continuer lexcution qui se termine imprativement par un appel free(). Noubliez jamais de librer la mmoire que vous avez alloue, mme si cest la n de votre programme. La raison est quun dveloppement ultrieur dans votre programme pourrait faire que ce qui tait la n ne le soit plus. Si vous navez pas libr la mmoire, vous ny penserez pas forcment en tendant votre programme.

La fonction calloc()
La fonction calloc() alloue aussi de la mmoire mais, au lieu dallouer un groupe doctets comme le fait malloc(), calloc() alloue un groupe dobjets. La zone de

http://fribok.blogspot.com/

mmoire alloue est remise zro et la fonction retourne un pointeur vers le premier octet de la zone. Si lallocation ne peut tre satisfaite, calloc() se contente de renvoyer NULL. Voici son prototype :
void *calloc(size_t num, size_t size);

On alloue (ou, plus exactement, on tente dallouer) num blocs de size octets chacun. Le programme du Listing 20.3 donne un exemple dutilisation de cette fonction. Listing 20.3 : Utilisation de calloc() pour allouer dynamiquement de la mmoire
1:/* Utilisation de calloc(). */ 2: 3:#include <stdlib.h> 4:#include <stdio.h> 5: 6:int main() 7:{ 8:unsigned num; 9:int *ptr; 10: 11:printf("Indiquez le nombre dint allouer: "); 12:scanf("%d", &num); 13: 14:if(NULL == (ptr = calloc(num, sizeof(*ptr))) 15:{ 16:perror("Lallocation de mmoire na pas t possible "); 17:exit(EXIT_FAILURE); 18:} 19:puts("Lallocation de mmoire a russi.\n"); 20: 21:free(ptr); 22:exit(EXIT_SUCCESS); 23:} Indiquez le nombre dint allouer: 10000 Lallocation de mmoire a russi.

Analyse Ce programme na effectu aucune vrication de la valeur entre par lutilisateur. Donc :

Si celui-ci tape une valeur ngative, comme elle est range dans un unsigned, elle "ressemblera" un nombre positif trs grand. Sil tape une valeur trs grande, suprieure ce que peut contenir un unsigned (par exemple, 99999 sur un PC), la valeur sera tronque et ce qui sera pass calloc() naura rien voir avec la valeur tape.

Il ne nous parat pas utile den dire davantage.

http://fribok.blogspot.com/

La fonction realloc()
Cette fonction modie la taille dun bloc mmoire prcdemment allou par un appel malloc() ou calloc(). Voici son prototype :
void *realloc(voit *ptr, size_t size);

Le pointeur ptr pointe sur le bloc de mmoire original. Largument size indique non pas le supplment de mmoire quon veut obtenir, mais la taille totale quon veut donner au bloc (infrieure ou suprieure celle du bloc original). Plusieurs cas sont possibles :

Sil y a assez de place pour satisfaire la requte, un nouveau bloc est allou et ptr contient son adresse. Le contenu de la zone de mmoire supplmentaire est indtermin, lancien contenu tant inaltr. Sil ny a pas assez de place, la fonction renvoie NULL et le contenu de lancien bloc nest pas altr. Si ptr contient NULL, realloc() se comporte comme malloc(). Si size vaut zro et que ptr ne vaut pas NULL, la zone prcdemment alloue et pointe par ptr est libre et la fonction renvoie NULL.

Le programme du Listing 20.4 montre un exemple simple dutilisation de realloc(). Listing 20.4 : Utilisation de realloc() pour modier la taille dun bloc allou dynamiquement
1: /* Utilisation de realloc() pour modifier la taille 2:dun bloc allou dynamiquement. */ 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <string.h> 6: 7:int main() 8:{ 9:char buf[80], *message; 10: 11:/* Entre dune chane de caractres. */ 12: 13:puts("Tapez une lignede texte."); 14:lire_clavier(buf, sizeof(buf)); 15: 16:/* Allouer le bloc initial et y copier la chane. */ 17: 18:message = realloc(NULL, strlen(buf)+1); 19:strcpy(message, buf); 20: 21:/*Afficher ce quon vient de lire au clavier. */ 22:

http://fribok.blogspot.com/

23:puts(message); 24: 25:/* Demander une autre chane lutilisateur. */ 26: 27:puts("Tapez une autre lignede texte."); 28:lire_clavier(buf, sizeof(buf)); 29: 30:/* Augmenter la taille du bloc prcdent et concatner 31:les deux chanes de caractres dans ce bloc. */ 32:if(NULL == ( 33:message = realloc(message, (strlen(message)+ strlen(buf)+1))) 34:{ 35:perror("Erreur de rallocation mmoire "); 36:exit(EXIT_FAILURE); 37:} 38:strcat(message, buf); 39: 40:/* Afficher la chane rsultante. */ 41: 42:puts(message); 43: 44:/* Terminer proprement en librant la totalit du bloc. */ 45: 46:realloc(message, NULL); 47:exit(EXIT_SUCCESS); 48:}

Voici un exemple dexcution :


Tapez une lignede texte. Loeil tait dans la tombe Loeil tait dans la tombe Tapez une autre lignede texte. et regardait Can. Loeil tait dans la tombe et regardait Can.

Analyse Le programme demande lutilisateur de taper une chane de caractres (ligne 13). Une fois que celui sest excut (ligne 14), la chane est lue dans un tableau de caractres, buf, ayant une longueur xe de 80 caractres. Cette chane est ensuite copie dans une zone de mmoire acquise dynamiquement (ligne 18). On notera lutilisation de realloc() avec NULL en premier argument, quivalente de malloc(). La taille de cette zone est juste sufsante pour loger la chane de caractres lue. Aprs avoir demand une seconde chane de caractres, on appelle realloc() en lui passant en arguments le pointeur sur la zone prcdemment alloue et la somme des longueurs des deux chanes (ligne 32). Il ne reste plus qu joindre les deux chanes au moyen de la fonction strcat() de la ligne 38, et librer la zone (avec une longueur nulle) par le realloc() de la ligne 46. Cet exemple illustrait les diffrents cas que peut

http://fribok.blogspot.com/

rencontrer la fonction realloc(). Bien entendu, prfrez malloc() (ou calloc()) pour allouer un nouvel espace, et free() pour librer la mmoire.

La fonction free()
Nous avons dj rencontr cette fonction de libration de mmoire alloue dynamiquement dans lexemple du Listing 20.2. Le pool de mmoire dans lequel on effectue des prlvements pour satisfaire les appels malloc(), calloc() ou realloc() nest pas inni ; il convient de restituer ce qui a t acquis dans un programme avant de passer la main au systme dexploitation. La libration dun bloc de mmoire seffectue en appelant la fonction free() dont le prototype est le suivant :
void free(void *ptr);

Attention, cette fonction ne renvoie rien. La mmoire pointe par ptr est restitue au pool de mmoire. Si ptr vaut NULL, la fonction ne fait rien du tout. Le programme du Listing 20.5 illustre son utilisation. Listing 20.5 : Utilisation de la fonction free() pour restituer de la mmoire acquise dynamiquement
1:/* Utilisation de free() pour librer 2:de la mmoire acquise dynamiquement. */ 3:#include <stdio.h> 4:#include <stdlib.h> 5:#include <string.h> 6: 7:#define BLOCKSIZE 30000 8: 9:int main() 10:{ 11:void *ptr1, *ptr2; 12: 13:/* Allouer un bloc. */ 14: 15:if(NULL == (ptr1 = malloc(BLOCKSIZE))) 16:{ 17:printf("Il a t impossible dallouer%d octets.\n", 18:BLOCKSIZE); 19:exit(EXIT_FAILURE); 20:} 21:printf("\nPremire allocation de%d octets russie.", 22:BLOCKSIZE); 23: 24:/* Essayer dallouer un autre bloc. */ 25: 26:if(NULL == (ptr2 = malloc(BLOCKSIZE)))

http://fribok.blogspot.com/

27:{ 28:printf("Le second essai pour allouer%d octets a chou.\n", 29:BLOCKSIZE); 30:exit(EXIT_FAILURE); 31:} 32: 33:/* Si lallocation russit, afficher un message , 34:librer les deux blocs et quitter le programme. */ 35: 36:printf("\nSeconde allocation de%d octets russie.\n", 37:BLOCKSIZE); 38: 39:/* Librer les deux blocs. */ 40:free(ptr1); 41:free(ptr2); 42:exit(EXIT_SUCCESS); 58:} Premire allocation de 30000 octets russie. Seconde allocation de 30000 octets russie.

Analyse Ce programme va tenter dallouer dynamiquement deux blocs de BLOCKSIZE octets chacun (ici, 30 000). La premire allocation seffectue la ligne 15 en appelant malloc(). Aux lignes 15 19, on teste la russite de lopration. Si elle choue, on afche un message et on sen va. On va ensuite tenter dallouer un second bloc distinct du premier (ligne 26). Si lopration choue, inutile de continuer : on afche un message et on sen va. Si ces deux oprations ont russi, on afche un message, on libre les deux blocs et on sen va.
eils Cons

faire Acqurir de la mmoire et ne pas la librer quand on nen a plus besoin est condamnable. Indiquer la taille de lespace mmoire allouer en utilisant sizeof(*poin teur). Le prprocesseur est capable de retrouver le type de llment point par pointeur et den calculer la taille avec sizeof(). ne pas faire Supposer quun appel malloc(), calloc() ou realloc() est toujours couronn de succs. Vriez toujours que la fonction na pas renvoy NULL.

http://fribok.blogspot.com/

Manipulation de blocs de mmoire


Dans la bibliothque standard C, il existe des fonctions pour manipuler des blocs de mmoire qui permettent de faire des initialisations ou des copies de bloc bloc, bien plus rapidement, par exemple, quavec une boucle for.

La fonction memset ()
Cette fonction sert donner tous les octets dun bloc de mmoire la mme valeur. Son prototype se trouve dans string.h. Il est le suivant :
void *memset(void *dest, int c, size_t count);

Largument dest pointe sur le bloc de mmoire, c est le caractre de garnissage et count est le nombre doctets (de caractres) de la zone quon veut initialiser. La valeur de retour est dest, ou NULL en cas derreur. Cest surtout pour initialiser des blocs de caractres que memset() est intressante. Pour dautres types de variable, cette fonction ne peut gure tre utilise quavec la valeur 0. Nous verrons un exemple dutilisation de cette fonction dans le Listing 20.6.

La fonction memcpy()
Cette fonction copie des blocs dinformations dun bloc de mmoire dans un autre, sans tenir compte du type. Cest simplement une copie lidentique, octet par octet. Son prototype se trouve dans string.h. Cest le suivant :
void *memcpy(void *dest, const void *src, size_t n);

Les arguments dest et src pointent respectivement vers la zone destinataire et la zone source, et n indique le nombre doctets copier. La valeur de retour est dest. Si les deux blocs se recouvrent, la recopie nest en gnral pas correcte, certaines parties de la source pouvant tre recouvertes avant dtre copies. Dans ce cas, il faut utiliser memmove(), de mme prototype que memcpy().

La fonction memmove()
memmove() est pratiquement identique memcpy() dont elle constitue un perfectionnement lorsquil y a recouvrement des blocs copier. Son prototype se trouve dans string.h. Cest le suivant :
void *memmove(void *dest, const void *src, size_t n);

http://fribok.blogspot.com/

dest et src pointent respectivement vers la zone destinataire et la zone source, et n indique le nombre doctets copier. La valeur de retour est dest. Mme si les deux blocs se recouvrent, la copie seffectue correctement. Cette fonction devant tenir compte du cas particulier o les zones mmoire se chevauchent, elle est un peu moins rapide que memcpy(). Le Listing 20.6 montre une application des trois fonctions memset(), memcpy() et memmove(). Listing 20.6 : Exemple dutilisation de memset(), memcpy() et memmove()
1:/* Exemple demploi de memset(), memcpy(), st memmove(). */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include <string.h> 5: 6:char message1[60] = "Le chne, un jour, dit au roseau"; 7:char message2[60] = "abcdefghijklmnopqrstuvwxyz"; 8:char temp[60]; 9:int main() 10:{ 11:printf("\nmessage[l] avant memset():\t%s", message1); 12:memset(message1+5, 0, 10); 13:printf("\nmessage[1] aprs memset():\t%s", message1); 14: 15:strcpy(temp, message2); 16:printf("\n\nmessage original:%s", temp); 17:memcpy(temp+4, temp+16, 10); 18:printf("\nAprs memcpy, sans recouvrement:\t%s", temp); 19:strcpy(temp, message2); 20:memcpy(temp+6, temp+4, 10); 21:printf("\nAprs memcpy() avec recouvrement:\t%s", temp); 22: 23:strcpy(temp, message2); 24:printf("\n\nMessage original:%s", temp); 25:memmove(temp+4, temp+16, 10); 26:printf("\nAprs memmove() sans recouvrement:\t%s", temp); 27:strcpy(temp, message2); 28:memmove(temp+6, temp+4, 10); 29:printf("\nAprs memmove() avec recouvrement:\t%s\n", temp); 29:exit(EXIT_SUCCESS); 30:} message[l] avant memset():Le chne, un jour, dit au roseau message[1] aprs memset():Le ch0000000000ur, dit au roseau message original: abcdefghijklmnopqrstuvwxyz Aprs memcpy() sans recouvrement:abcdqrstuvwxyzopqrstuvwxyz Aprs memcpy() avec recouvrement:abcdefefefefefefqrstuvwxyz Message original: abcdefghijklmnopqrstuvwxyz Aprs memmove() sans recouvrement: abcdqrstuvwxyzopqrstuvwxyz Aprs memmove() avec recouvrement: abcdefefghijklmnqrstuvwxyz

http://fribok.blogspot.com/

Analyse Pas de commentaire pour memset(). La notation message1+5 permet de spcier le point de dpart de laction de memset() (6e caractre de message1). Il en rsulte que les caractres 6 15 sont remplacs par des zros. Quand il ny a pas recouvrement (ligne 17), on constate que memcpy() fonctionne correctement. En revanche, linstruction de la ligne 20, la source tant place deux positions plus gauche que la destination, le rsultat montre le redoublement des caractres "fe" situs entre les deux points de dpart. Les deux exemples de memmove() (lignes 25 et 28) montrent que tout se passe bien dans les deux cas.

Oprations sur les bits


Vous savez que lunit de base pour le stockage des informations est le bit. Il est quelquefois trs pratique de pouvoir manipuler ces bits partir dun programme C. cette n, ce langage met plusieurs outils votre disposition. Vous pouvez manipuler les bits dune variable entire laide des oprateurs bit bit. Le bit tant la plus petite unit denregistrement, il ne peut prendre que lune des deux valeurs 0 ou 1. Ces oprateurs ne sappliquent quaux types entiers : char, int, et long. Pour comprendre le fonctionnement de ces oprateurs, vous devez matriser la notation binaire, puisquil sagit de la technique utilise par lordinateur pour enregistrer ces entiers. Cette notation est dtaille en Annexe C. Lutilisation la plus frquente des oprateurs bit bit consiste faire dialoguer directement le programme C avec la machine. Ce sujet nest pas trait dans ce chapitre, car il sort du cadre de ce livre. Nous allons prsenter les autres applications possibles.

Les oprateurs de dcalage


Le rle des deux oprateurs de dcalage est de dplacer les bits dune variable entire dun certain nombre de positions. Loprateur (<<) dcale les bits vers la gauche et loprateur (>>) les dcale vers la droite. Voici la syntaxe utilise :
x << n x >> n

Chacun de ces oprateurs dcale les bits de la variable x de n positions dans la direction correspondante. Lorsque le dcalage seffectue vers la droite, les n bits suprieurs reoivent la valeur zro. Lorsque ce dcalage se fait vers la gauche, ce sont les n bits de plus bas niveau qui reoivent la valeur zro. Voici quelques exemples :

http://fribok.blogspot.com/

La valeur binaire 00001100 (12, en dcimal) dcale 2 fois droite devient 00000011 (3, en dcimal). La valeur binaire 00001100 (12, en dcimal) dcale 3 fois gauche devient 01100000 (96, en dcimal). La valeur binaire 00001100 (12, en dcimal) dcale 3 fois droite devient 00000001 (1, en dcimal). La valeur binaire 00110000 (48, en dcimal) dcale 3 fois gauche devient 10000000 (128, en dcimal).

Ces oprateurs permettent dans certains cas de multiplier ou de diviser une variable entire par une puissance de 2. En dcalant un entier de n positions vers la gauche, vous obtenez une multiplication par 2n condition de ne "perdre" aucun bit signicatif dans cette opration. Ce mme dcalage vers la droite permet dobtenir une division entire par 2n puisque lon perd la fraction dcimale du rsultat. Si vous dcalez dune position vers la droite, par exemple, la valeur 5 (00000101) pour la diviser par deux, le rsultat sera 2 (00000010), plutt que 2,5. Le Listing 20.7 prsente une utilisation de ces oprateurs. Listing 20.7 : Les oprateurs de dcalage
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: /* Les oprateurs de dcalage. */ #include <stdio.h> #include <stdlib.h> int main() { unsigned int y, x = 255; int count; printf("Valeur dcimale\t\tdcalage gauche\trsultat\n"); for (count = 1; count < 8; count++) { y = x << count; printf("%d\t\t%d\t\t%d\n", x, count, y); } printf("\n\nValeur dcimale\t\tdcalage droite\trsultat\n"); for (count = 1; count < 8; count++) { y = x >> count; printf("%d\t\t%d\t\t%d\n", x, count, y); } exit(EXIT_SUCCESS); }

http://fribok.blogspot.com/

Lexcution de ce programme donne le rsultat suivant :


Valeur dcimale 255 255 255 255 255 255 255 Valeur dcimale 255 255 255 255 255 255 255 Dcalage gauche 1 2 3 4 5 6 7 Dcalage droite 1 2 3 4 5 6 7 rsultat 254 252 248 240 224 192 128 rsultat 127 63 31 15 7 3 1

Les oprateurs logiques bit bit


Le Tableau 20.1 prsente les trois oprateurs logiques bit bit qui permettent de manipuler les bits dune donne de type entier. Ces oprateurs semblent analogues aux oprateurs boolens tudis prcdemment, mais le rsultat obtenu est diffrent. Tableau 20.1 : Les oprateurs logiques bit bit
Oprateur & | ^ Description
ET OU inclusif OU exclusif

Ces oprateurs binaires attribuent la valeur 0 ou 1 aux bits du rsultat en fonction des bits constituant les oprandes. Ils fonctionnent de la faon suivante :

Loprateur ET bit bit attribue la valeur 1 un bit du rsultat lorsque les deux bits correspondants des oprandes ont la valeur 1. Dans le cas contraire, il dnit le bit 0. Cet oprateur est utilis pour dsactiver ou remettre zro un ou plusieurs bits dans une valeur. Loprateur OU inclusif bit bit attribue la valeur 0 un bit du rsultat si les deux bits correspondants des oprandes ont la valeur 0. Dans le cas contraire, il attribue la valeur 1. Cet oprateur est utilis pour activer ou dnir un ou plusieurs bits dans une valeur.

http://fribok.blogspot.com/

Loprateur OU exclusif bit bit attribue la valeur 1 un bit du rsultat si les bits correspondants des oprandes sont diffrents. Dans le cas contraire, il attribue la valeur 0.

Voici quelques exemples mettant en uvre ces oprateurs :


Opration
ET

Exemple 11110000 & 01010101 01010000

OU inclusif

11110000 | 01010101 11110101

OU exclusif

11110000 ^ 01010101 10100101

Voici pourquoi on peut utiliser le ET bit bit et le OU inclusif bit bit pour remettre zro et dnir, respectivement, certains bits dune valeur entire. Supposons que vous vouliez remettre zro les bits en positions 0 et 4 dune variable de type char, tout en conservant la valeur initiale des autres bits. Vous obtiendrez ce rsultat en combinant cette variable avec la valeur binaire 11101110 laide de loprateur ET. Pour chaque valeur 1 du second oprande, le rsultat sera gal la valeur correspondante dans le premier oprande :
0 & 1 == 0 1 & 1 == 1

Pour chaque valeur 0 du second oprande, le rsultat sera gal 0 quelle que soit la valeur correspondante dans le premier oprande :
0 & 0 == 0 1 & 0 == 0

Loprateur OU opre de faon similaire. Pour chaque valeur 1 du second oprande, le rsultat sera gal 1 et pour chaque valeur 0 du second oprande, la valeur correspondante dans le premier oprande restera inchange :
0 1 0 1 | | | | 1 1 0 0 == == == == 1 1 0 1

http://fribok.blogspot.com/

Loprateur complment
Loprateur unaire complment (~) est le dernier oprateur bit bit. Sa fonction consiste inverser tous les bits de son oprande. 254 (11111110), par exemple, va se transformer en 1 (00000001). Tous les exemples de cette section font intervenir des variables de type char constitues de 8 bits. Le fonctionnement de ces oprations est identique dans le cas de variables plus longues comme les types int et long.

Les champs de bits dans les structures


Nous allons terminer cette tude avec les champs de bits des structures. Vous avez appris au Chapitre 11 dnir vos propres structures de donnes et les adapter aux besoins de votre programme. Les champs de bits permettent de personnaliser encore davantage ces donnes et de rduire la mmoire ncessaire. Un champ de bits est un membre de structure constitu dun certain nombre de bits. Vous dclarez ce champ en indiquant le nombre de bits ncessaires pour recevoir les donnes. Supposons que vous crez une base de donnes des employs pour votre entreprise. Cette base de donnes va contenir de nombreux lments dinformation du type oui/non pour indiquer si lemploy est diplm de luniversit, par exemple, ou sil participe au plan de prvention dentaire. Chacune de ces informations peut tre enregistre en un seul bit, la valeur 1 indiquant une rponse positive et la valeur 0, une rponse ngative. La plus petite entit utilise dans une structure avec les types de donnes standards du C est le type char. Vous pouvez bien sr faire appel ce type dans votre membre de structure pour enregistrer vos donnes oui/non, mais sept bits sur les huit qui constituent la variable char seront inutiliss. Les champs de bits permettent denregistrer huit rponses oui/non dans une seule variable char. Les valeurs oui/non ne sont pas les seules applications des champs de bits. Imaginons que lentreprise de notre exemple offre trois possibilits pour une assurance complmentaire maladie. Votre base de donnes devra enregistrer lassurance choisie par chaque employ. La valeur 0 pourrait signier aucune assurance souscrite, et les valeurs 1, 2, et 3 pourrait reprsenter la souscription lune de ces assurances. Un champ de bits constitu de 2 bits sera sufsant pour enregistrer les quatre valeurs de 0 3. Un champ de bits sur trois positions pourra de la mme faon recevoir des valeurs entre 0 et 7, quatre bits pourront enregistrer des valeurs comprises entre 0 et 15, etc. On accde aux champs de bits comme un membre de structure ordinaire. Ils sont tous du type unsigned int et leur taille est indique (en bits) aprs deux points, la suite du nom du

http://fribok.blogspot.com/

membre. Les lignes qui suivent dnissent une structure constitue dun membre univer site sur un bit, et dun membre sante de 2 bits :
struct emp_data { unsigned universite unsigned sante ... }; : 1; : 2;

Les trois points indiquent la prsence ventuelle dautres membres dans cette structure, de type champ de bits, ou constitus dun type de donne standard. Notez que les champs de bits doivent apparatre en tte de la dnition de la structure, et que lon accde ce type de membre de faon standard. La dnition de structure prcdente peut tre complte comme suit :
struct emp_data { unsigned universite : 1; unsigned sante : 2; char fname[20]; char lname[20]; char ssnumber[10]; };

Vous pouvez ensuite dclarer le tableau de structures suivant :


struct emp_data workers[100];

Voici comment attribuer des valeurs au premier lment du tableau :


workers[0].universite = 0; workers[0].sante = 2; strcpy(workers[0].fname, "Mildred");

Vous pouvez bien sr simplier votre code en utilisant les constantes symboliques OUI et NON avec des valeurs de 0 et 1 lorsque vous travaillez avec des champs dun bit. Vous devez considrer chaque champ de bits comme un entier non sign constitu dun nombre donn de bits. On pourra attribuer chacun de ces champs des valeurs entre 0 et 2n 1, n tant le nombre de bits du champ. Si vous attribuez une valeur nappartenant pas cet intervalle, le compilateur ne signalera pas votre erreur, et vous obtiendrez des rsultats errons.
eils Cons

faire Utiliser des constantes dnies OUI et NON ou VRAI et FAUX lorsque vous travaillez au niveau des bits. Le code sera plus facile relire quen utilisant des 0 et des 1.

http://fribok.blogspot.com/

ne pas faire Dnir des champs avec 8 ou 16 bits. Utilisez plutt une variable quivalente du type char ou int.

Rsum
Dans ce chapitre, nous avons trait plusieurs sujets : les conversions de types, lallocation de mmoire dynamique et les fonctions oprant directement sur la mmoire : initialisation et copie. Vous avez aussi vu comment et quand utiliser la coercition sur les variables et les pointeurs. Le mauvais usage de la coercition est une des causes derreur les plus frquentes en C. Vous avez enn tudi les diffrentes mthodes de manipulation au niveau des bits.

Q&R
Q Quel est lavantage de lallocation de mmoire dynamique ? Pourquoi est-ce que je ne peux pas tout simplement dclarer la place mmoire dont jai besoin dans mon programme source ? R Parce que vous ne la connaissez pas toujours. La place ncessaire peut dpendre des donnes que vous allez traiter. Q Pourquoi dois-je toujours librer la mmoire acquise dynamiquement ? R Plus vos programmes se rapprocheront de la ralit, plus ils grossiront et plus vous aurez besoin de mmoire. Ce nest pas une denre inpuisable et il faut apprendre la grer. Cest particulirement vrai dans un environnement multitche comme Windows ou Linux. Q Quarrivera-t-il si je rutilise une chane de caractres sans appeler realloc()? R Si vous ne risquez pas de dpasser la place alloue pour votre chane, vous navez pas besoin dappeler realloc(). Noubliez pas que C est un langage permissif, qui vous autorise donc faire des choses que vous ne devriez, raisonnablement, jamais faire. Si vous crasez une chane par une autre, plus grande, vous allez dborder de la place alloue et, au mieux, faire arrter votre programme sur une erreur de segmentation et, au pire, pitiner autre chose : variable, programme. Cest pour viter ce genre de problmes que vous devez pralablement appeler realloc(). Q Quel est lavantage de la famille mem...()? Pourquoi ne pas utiliser tout simplement une boucle for? R Ce nest pas interdit, mais les fonctions dont vous parlez font la mme chose plus rapidement, avec, cependant, des limitations (surtout pour memset()).

http://fribok.blogspot.com/

Q Quelles sont les applications des oprateurs de dcalage et des oprateurs logiques bit bit ? R Ces oprateurs sont utiliss la plupart du temps lorsque le programme dialogue directement avec la machine. Ce type dopration ncessite souvent la gnration et linterprtation dun modle spcique de bits. Ce sujet nest pas trait dans ce livre. Les oprateurs de dcalage permettent, dans certains cas, de diviser ou de multiplier des valeurs entires par des puissances de 2. Q Quels sont les avantages de lutilisation des champs de bits ? R Considrons le cas dun sondage qui constitue un exemple analogue celui fournit dans ce chapitre. Les utilisateurs doivent rpondre aux questions poses par oui ou par non. Si vous posez cent questions dix mille personnes et que vous enregistriez chaque rponse dans un type char, vous devrez disposer de 10 000 100 octets de mmoire (un caractre occupe en effet 1 octet). Cela reprsente un million doctets. Si vous optez, dans ce cas, pour les champs de bits, vous pourrez enregistrer huit rponses par octet (puisquun octet est constitu de 8 bits). Le besoin en mmoire se rduit ainsi 130 000 octets.

Atelier
Latelier vous propose quelques questions permettant de tester vos connaissances sur les sujets que nous venons daborder dans ce chapitre.

Quiz
1. Quelle diffrence y a-t-il entre malloc() et calloc()? 2. Quelle est la raison la plus courante dutiliser la coercition sur une variable numrique ? 3. Quel est le type du rsultat obtenu par lvaluation des expressions suivantes, sachant que c est de type char; i, de type int; l, de type long et f, de type float? a) (c + i + 1) b) (i + 32) c) (c + A) d) (i + 32.0) e) (100 + 1.0) 4. Que signie lexpression "allocation de mmoire dynamique" ? 5. Quelle diffrence y a-t-il entre memcpy() et memmove()?

http://fribok.blogspot.com/

6. Votre programme utilise une structure qui doit stocker (dans lun de ses membres) le jour de la semaine sous la forme dune valeur entre 1 et 7. Quelle technique faut-il choisir pour utiliser au mieux votre mmoire ? 7. Quel est, en dnissant une structure, le minimum de mmoire ncessaire pour enregistrer la date courante ? (Sous la forme mois/jour/anne ; considrez 1900 comme point de dpart pour le compte des annes.) 8. Quelle est la valeur de 10010010 << 4? 9. Quelle est la valeur de 10010010 >> 4? 10. Quelles sont les diffrences entre les rsultats des deux expressions suivantes :
(01010101 ^ 11111111 ) ( ~01010101 )

Exercices
1. crivez une commande malloc() qui alloue de la place pour 1 000 lments de type long. 2. crivez une commande calloc() qui alloue de la place pour 1 000 lments de type long. 3. En supposant que vous ayez dclar ainsi un tableau :
float data[1000];

donnez deux faons dinitialiser tous ses lments zro, dont lune avec une boucle et lautre, sans. 4. CHERCHEZ LERREUR : Y a-t-il une erreur dans les instructions ci-aprs ?
void fonc() { int nombre1=100, nombre2=3; float reponse; reponse = nombre1 / nombre2; printf("%d/%d =%lf\n", nombre1, nombre2, reponse); }

5. CHERCHEZ LERREUR : Y a-t-il une erreur dans les instructions ci-aprs ?


void *p; p = (float*) malloc(sizeof(float)); *p = 1.23;

http://fribok.blogspot.com/

6. CHERCHEZ LERREUR : La structure suivante est-elle correcte ?


struct quiz_answers { char student_name[15]; unsigned answer1 : 1; unsigned answer2 : 1; unsigned answer3 : 1; unsigned answer4 : 1; unsigned answer5 : 1; }

Les exercices qui suivent ne sont pas corrigs en Annexe G. 7. Crez un programme qui fait appel tous les oprateurs logiques bit bit. Loprateur doit tre appliqu un nombre, puis de nouveau au rsultat obtenu. tudiez la sortie du programme an de bien comprendre le processus. 8. Crez un programme qui afche la valeur binaire dun nombre (utilisez pour cela les oprateurs bit bit).

http://fribok.blogspot.com/

21
Utilisation avance du compilateur
Dans ce chapitre, nous allons tudier quelques fonctionnalits supplmentaires du compilateur C :

Utilisation de plusieurs chiers sources Emploi du prprocesseur Exploitation des arguments de la ligne de commande

http://fribok.blogspot.com/

Utilisation de plusieurs chiers sources


Jusquici, tous vos programmes C taient constitus dun seul et unique chier source. Pour de simples petits programmes, ctait bien sufsant. Mais rien nempche de diviser le chier source en plusieurs chiers. Cest ce quon appelle la programmation modulaire. Quel intrt y a-t-il procder ainsi ?

Avantages de la programmation modulaire


La principale raison dutiliser la programmation modulaire est lie de trs prs la programmation structure et une forme dcriture faisant un usage intensif des fonctions. Au fur et mesure que vous acquerrez de lexprience, vous serez amen crer des fonctions dintrt gnral que vous pourrez utiliser, non seulement dans le programme pour lequel vous les avez crites lorigine, mais aussi dans dautres programmes. Par exemple, vous pourriez crire une collection de fonctions destines afcher des informations sur lcran. En conservant ces fonctions dans un chier spar, il vous sera facile de les remployer dans diffrents programmes devant faire des afchages sur lcran. Lorsque vous crivez un programme faisant appel plusieurs chiers de code source, chaque chier est appel un module.

Techniques de programmation modulaire


Un programme C ne peut avoir quune seule fonction main(). Le module qui contient cette fonction est appel le module principal et les autres, les modules secondaires. On associe gnralement un chier den-tte spar chaque module secondaire, comme nous allons bientt le voir. Pour linstant, considrons quelques exemples simples illustrant les bases de la programmation modulaire. Les Listing 21.1, 21.2, et 21.3 vous montrent respectivement le module principal, le module secondaire et le chier den-tte dun programme qui lit un nombre donn par lutilisateur et afche son carr. Listing 21.1 : list21_1.c : le module principal
1:/* Entrer un nombre et afficher son carr. */ 2:#include <stdio.h> 3:#include <stdlib.h> 4:#include "calc.h" 5: 6:int main() 7:{ 8:int x; 9: 10:printf("Tapez un nombre entier: "); 11:scanf("%d", &x);

http://fribok.blogspot.com/

12:printf("\nLe carr de%d est%ld.\n", x, sqr(x)); 13:exit(EXIT_SUCCESS); 14:}

Listing 21.2 : calc.c : le module secondaire


1:/* Module contenant une fonction de calcul. */ 2: 3:#include "calc.h" 4: 5:long sqr(int x) 6:{ 7:return (long)x * x; 8:}

Listing 21.3 : calc.h : le chier den-tte pour calc.c


1:/* calc.h: fichier den-tte pour calc.c. */ 2: 3:long sqr(int x); 4: 5:/* fin de calc.h */ Tapez un nombre entier: 525 Le carr de 525 est 275625.

Analyse Regardons en dtail les trois composantes de ce programme. Le chier den-tte, calc.h, contient le prototype de la fonction sqr() appele dans calc.c. Comme tout module appelant la fonction sqr() a besoin de connatre son prototype, il faut donc inclure calc.h dans calc.c. Le module secondaire, calc.c, contient la fonction sqr(). On peut y voir linclusion de calc.h dont le nom est plac entre guillemets et non entre les signes habituels < et >. Nous en verrons la raison un peu plus loin. Le module principal, list21_1.C, contient la fonction main(). Il contient aussi un #include du chier den-tte calc.h. Une fois que vous avez cr ces chiers, comment allez-vous les associer pour les compiler et confectionner le module excutable ? Cest au compilateur que va revenir cette tche. Si vous utilisez une ligne de commande, vous crirez, par exemple :
xxx list21_1.c calc.c -o list21_1

o xxx reprsente la commande de votre compilateur, priori gcc ou cc.

http://fribok.blogspot.com/

Avec des environnements intgrs, vous utiliserez gnralement un menu. Le manuel de rfrence ou laide en ligne du compilateur utilis vous indiquera le dtail du processus suivre. De la sorte, le compilateur va produire les modules list21_1.o ET calc.o (list21_1.obj et calc.obj, sous certains systmes) et lditeur de liens va les lier, en compagnie des fonctions de bibliothque ncessaires, pour fabriquer list21_1 (ou list21_1.exe sur Windows). Dans certains cas, comme avec la ligne de commande ci-dessus, vous ne verrez pas les chiers correspondant aux modules.

Composantes des modules


Comme vous le voyez, tout cela reste trs simple. La seule question qui se pose rellement est de savoir ce que chaque module doit contenir. Nous allons vous donner quelques indications gnrales. Le module secondaire devrait renfermer les fonctions utilitaires, celles qui sont rutilisables dans dautres programmes. Certains programmeurs crent un module par fonction, ce qui est sans doute excessif. Mieux vaut crer un module par type de fonction. Mettez, par exemple, dans un mme module, les fonctions qui ont trait au clavier, dans un autre, celles qui concernent lcran, dans un troisime, celles qui font certaines manipulations particulires des chanes de caractres, et ainsi de suite. Le procd que nous venons de voir pour compiler les modules isols est gnralisable plus de deux modules. Peu importe lordre dans lequel vous allez crire la liste de vos modules. En ce qui concerne les chiers den-tte, il faut, l encore, se garder den multiplier le nombre. Les programmeurs en crivent gnralement autant de modules, raison dun par module, dans lesquels ils font gurer le prototype des fonctions du module correspondant. En gnral, on vite de mettre des instructions excutables dans un chier den-tte. On y trouve principalement des prototypes de fonctions et des #define (dnissant les constantes symboliques et les macros). Comme un mme chier den-tte peut tre inclus dans plusieurs modules source, il faut viter que certaines portions ne soient compiles plusieurs fois. Cela se fait laide de directives conditionnelles que nous tudierons plus loin, dans ce mme chapitre.

Variables externes et programmation modulaire


Souvent, le seul moyen de communiquer des donnes entre le module principal et les modules secondaires est dchanger des arguments et des valeurs de retour avec des fonctions. Il ny a, dans ce cas, aucune prcaution particulire prendre en ce qui concerne la

http://fribok.blogspot.com/

visibilit des variables. Mais il est parfois ncessaire quune ou plusieurs variables puissent tre vues (partages) par plusieurs modules diffrents. Au Chapitre 12, nous avons dit quune variable externe tait une variable dclare en dehors de toute fonction. Une telle variable est visible dans la totalit du chier source o elle est dclare. Cependant, elle nest visible que de lintrieur du module o elle se trouve. Si plusieurs modules sont prsents et quils doivent pouvoir utiliser cette variable, il est ncessaire de la dclarer laide du mot clef extern. Si, par exemple, vous voulez quune variable taux d interet soit visible par tous les modules, vous allez la dclarer dans lun dentre eux de la faon suivante :
float taux_d_interet;

en dehors de toute fonction. Dans les modules qui doivent partager cette variable, vous crirez :
extern float taux_d_interet;

Figure 21.1 Utilisation du mot cl extern pour rendre une variable visible par plusieurs modules.

/* module principal */ int x, y; int main() { ... ... }

/* module secondaire mod2.c */ extern int x; fonc2() { ... } ...

/* module secondaire mod1.c */ extern int x, y; fonc1() { ... } ...

Ce mot indique au compilateur quil ne doit pas rserver de place en mmoire pour cette variable. Cest ldition de liens que ladressage de cet avant-plan sera rsolu. La Figure 21.1 illustre ce mcanisme. Dans la Figure 21.1, la variable x est visible dans les trois modules, alors que la variable y nest visible que dans le module principal et dans le module secondaire mod1.c.

Utilisation des chiers .o


Une fois que vous avez crit et mis au point un module secondaire, vous pouvez le compiler et gnrer un chier objet. Ainsi, il nest plus ncessaire de le recompiler chaque fois que vous ditez un autre module de votre programme Le temps de compilation ainsi gagn

http://fribok.blogspot.com/

est dailleurs un autre avantage de la programmation modulaire. Vous tes alors en possession du module objet (chier .obj ou .o), de mme nom que le module source que le compilateur a plac sur le disque dur. Pour compiler un objet partir des sources dun module, en ligne de commande, vous devez utiliser loption -c si votre compilateur est cc ou gcc. Par exemple, les objets main.o calc.o sont obtenus ainsi :
gcc -c main.c gcc -c calc.c

Cette ligne illustre ce quest la compilation. Lorsque vous avez compil tous vos modules (et obtenu autant de chiers .o que de modules), vous passez ldition des liens, qui consiste rassembler tous ces objets en un seul de manire obtenir lexcutable. Si sur Unix (et Linux) lditeur de lien sappelle ld, vous pouvez linvoquer partir du compilateur (cc ou gcc). Vous indiquez alors sur la mme ligne de commande tous les objets et ajoutez loption -o pour spcier le nom de lexcutable gnrer. Reprenons notre exemple :
gcc main.o calc.o -o list21_1

Vous pouvez obtenir le mme rsultat dans un environnement intgr. Le manuel de rfrence de votre compilateur vous donnera toutes indications utiles sur ce point.
eils Cons

faire Crer des fonctions gnriques intelligemment regroupes par types, dans plusieurs chiers sources. ne pas faire Associer plusieurs modules dans lesquels se trouveraient plusieurs fonctions main().

Lutilitaire make
En dehors de trs petits programmes, on nutilise gnralement pas une ligne de commande, mais un chier Makele dans lequel on va dcrire lassociation des diffrents modules du projet, leur compilation, leur dition de liens et les bibliothques qui devront tre utilises. Lcriture correcte dun tel module peut devenir trs complexe et sort nettement des objectifs de ce livre. Nous nous contenterons de donner ici quelques indications gnrales. Le principe dun make, cest de dnir les dpendances qui existent entre les modules. Imaginons un projet qui associerait un programme principal, program.c et un module secondaire, second.c. Il existerait aussi deux chiers den-tte : program.h et second.h, appels dans program.c. Seul, second.h serait appel dans second.c. Dans program.c seraient appeles des fonctions prsentes dans second.c.

http://fribok.blogspot.com/

program.c est dit dpendant de deux chiers den-tte parce quil contient un #include de chacun deux. Si vous apportez une modication lun des deux chiers den-tte, vous devrez recompiler program.c. Mais, si cette modication ne concernait que program.h, il ne sera pas ncessaire de recompiler aussi second.c puisquil ne lutilise pas. second.c ne dpend que de second.h. Lutilitaire make (parfois appel nmake) va "deviner" les relations de dpendance daprs les dates des diffrents chiers et prendre ses dcisions de recompilation sur cette base. Pour vous donner une ide de ce que serait alors le chier Makele, nous vous le donnons ici sans explication. Faites attention : les lignes qui semblent commencer par des espaces commencent en ralit par une tabulation, ce qui est obligatoire dans la syntaxe dun chier Makele.
program: program.o second.o gcc program.o second.o -o program .c.o: gcc -o $@ -c $<

Le prprocesseur C
Le prprocesseur fait partie intgrante du compilateur proprement dit. Lorsque vous compilez un programme C, cest le prprocesseur qui (comme son nom le laisse deviner) va sattaquer en premier votre chier source. Une fois son travail fait, il va, de lui-mme, appeler le compilateur. Selon les diteurs de compilateurs, le prprocesseur peut ou non tre un module spar de celui du compilateur. Cela ne change rien son modus operandi. Le prprocesseur est directement concern par les directives qui gurent dans vos modules source. Il les dcode et cest le rsultat de ce traitement qui va tre soumis au compilateur. Normalement, vous ne voyez jamais ce chier intermdiaire qui est automatiquement supprim par le compilateur, une fois quil la utilis. Nous verrons, cependant, quil est possible de voir ce quil contient. Nous allons commencer par examiner les directives traites par le prprocesseur. Elles commencent toutes par le caractre dise (#).

La directive #define
Cette directive sert deux ns : dnir des constantes symboliques et crer des macros.

Macros de substitution
Au Chapitre 3, vous avez appris les bases de lutilisation des macros de substitution pour la cration de constantes symboliques. Leur forme gnrale est :
#define texte1 texte2

http://fribok.blogspot.com/

Cette directive dit au prprocesseur de remplacer toutes les occurrences de texte1 dans le programme par texte2, sauf lorsque texte1 est plac entre guillemets. Lusage le plus frquent de cette directive est donc de crer des constantes symboliques. Si, par exemple, votre programme contient les lignes suivantes :
#define MAX 1000 x = y * MAX; z = MAX 12;

Le code source est transform en :


x = y * 1000; z = 1000 12;

Leffet produit est identique celui que vous auriez obtenu en utilisant la fonction de remplacement de votre traitement de texte. Le code source lui-mme reste inchang, cest la copie intermdiaire qui sera passe au compilateur qui garde trace de ces transformations. Notez que cette substitution nest pas limite des noms de variables ou de constantes et peut sappliquer nimporte quelle chane de caractres du chier source. Par exemple :
#define ONVAVOIR printf ONVAVOIR("Hello, world");

Mais, en dehors de la production de codes sotriques et difcile relire, cette particularit est rarement utilise.

Cration de macros avec #define


Vous pouvez aussi utiliser #define pour crer des macros de type fonction qui sont, en quelque sorte, des notations abrges destines reprsenter quelque chose de plus compliqu. On les appelle parfois des "fonctions macro" parce que, tout comme les fonctions, elles acceptent des arguments. Ces arguments ne sont pas typs. Prenons un exemple. Considrons la directive :
#define MOITIE(valeur) ((valeur)/2)

Elle dnit une macro appele MOITIE qui accepte un argument appel valeur. Lorsque le prprocesseur rencontre la chane MOITIE(...) dans le texte du chier source (... reprsentant nimporte quoi), il remplace lensemble par le texte de dnition en reproduisant largument pass. Exemple :
resultat = MOITIE(10);

http://fribok.blogspot.com/

devient :
resultat = ((10)/2);

De la mme faon :
printf("%f\n", MOITIE(x[1]+ y[2]));

deviendra :
printf("%f\n", ((x[1]+ y[2])/2));

Une macro peut accepter plusieurs arguments, chacun dentre eux pouvant tre utilis plusieurs fois dans le texte de remplacement. Par exemple, la macro suivante, qui calcule la moyenne de cinq valeurs, accepte cinq arguments :
#define MOYENNE(u, v, w, x, y) (((u)+(v)+(w)+(x)+(y))/5)

Dans cette autre macro o intervient loprateur ternaire conditionnel, on dtermine la plus grande de deux valeurs. Elle utilise chaque argument deux fois (nous avons tudi loprateur conditionnel au Chapitre 4).
#define PLUSGRAND(x,y) ((x)>(y)?(x):(y))

Tous les arguments gurant dans la liste de la macro ne doivent pas obligatoirement tre utiliss dans le texte de remplacement. Ainsi, dans cet exemple, il ny a rien dillgal :
#define ADD(x, y, z) ((x)+(y))

En revanche, il faudra appeler ADD avec trois arguments dont le troisime ne servira rien, sinon se conformer la dnition de la macro. On voit, une fois de plus, que C ninterdit pas dcrire des btises ! Lemploi des parenthses est plus svrement rglement qu lintrieur des instructions "normales". En particulier, la premire parenthse ouvrante doit tre accole au nom de la macro. Cest de cette faon que le prprocesseur sait quil sagit dune macro et non dune simple dnition de constante. Dans lexemple ci-avant, crire :
#define ADD (x, y, z) ((x)+(y))

reviendrait dclarer une substitution gnralise de la chane ADD par la chane (x, y, z) ((x)+(y)), ce qui naurait pas du tout leffet escompt.

http://fribok.blogspot.com/

Il ne faut pas croire que les parenthses entourant chaque nom dargument soient une coquetterie. Elles sont indispensables pour viter des effets de bord parasites, parfois difcilement dcelables. Considrons lexemple simple suivant :
#define CARRE(x) x*x

Si on appelle CARRE avec un argument simple, comme x ou 3.14, il ny aura pas de problme. Mais, que va-t-il se passer si on crit :
z = CARRE(x+y);

Le prprocesseur va transformer cette instruction en :


z = x+y * x+y;

Ce nest pas du tout ce quon voulait faire. Alors que si on avait entour chaque argument dune parenthse :
z = CARRE((x)+ (y));

on aurait obtenu :
z = (x+y) * (x+y);

qui est sans doute plus conforme ce quon esprait. On peut apporter davantage de souplesse l utilisation des macros grce loprateur # prcdant immdiatement le nom dun argument. Celui-ci est alors transform en chane de caractres lors de lexpansion de la macro. Si on crit :
#define SORTIE(x) printf(#x)

et quon utilise cette macro comme ceci :


SORTIE(Salut, les copains!);

on obtiendra :
printf("Salut, les copains!");

Cette "caractrisation" prend en compte tous les caractres, mmes ceux qui ont un sens particulier et ceux qui demandent un caractre dchappement. Dans lexemple ci-avant, si on avait crit :
SORTIE("Salut, les copains!");

http://fribok.blogspot.com/

on aurait obtenu la substitution :


printf("\"Salut, les copains!\"");

Lexemple du Listing 21.4 vous prsente une application de loprateur (#). Mais, avant de vous y attaquer, il faut que nous tudions un autre oprateur, celui de concatnation (##). Cet oprateur concatne (joint) deux chanes de caractres dans lexpansion dune macro. Il ne traite pas les caractres dchappement. Son utilisation principale est de crer des suites de codes sources. Si, par exemple, vous dnissez une macro :
#define CHOP(x) fonc ## x salade = CHOP(3)(q, w);

il en rsultera lexpansion :
salade = fonc3 (q, w);

Vous constatez quainsi, vous pouvez modier le nom de la fonction appele, donc, en dnitive, le code source. Listing 21.4 : Utilisation de loprateur (#) dans une expansion de macro
1:/* Illustre lutilisation de loprateur # 2:dans lexpansion dune macro. */ 3:#include <stdio.h> 4:#include <stdlib.h> 5: 6:#define OUT(x) printf(#x " est gal %d.\n", x) 7: 8:int main() 9:{ 10:int valeur = 123; 11: 12:OUT(valeur); 13:exit(EXIT_SUCCESS); 14:} valeur est gal 123.

Analyse Loprateur (#) de la ligne 6 permet de reporter tel quel le nom de la variable passe en argument, sous forme de chane de caractres, dans lexpansion de la macro qui devient :
printf("valeur" " est gale %d.\n", valeur);

http://fribok.blogspot.com/

Macros ou fonctions ?
Vous venez de voir que les macros pouvaient tre utilises aux lieu et place de vritables fonctions, tout au moins dans des situations o le code rsultant est relativement court. Les macros peuvent dpasser une ligne mais, gnralement, elles deviennent trop difciles matriser en quelques lignes. Lorsque vous avez le choix entre une fonction ou une macro, laquelle devez-vous choisir ? Cest une question de compromis entre la taille et la vitesse dexcution du programme. Une dnition de macro voit son expansion directement insre dans le code gnr par le compilateur chaque fois quelle est appele. Si vous avez 100 appels de la macro, son expansion sera insre 100 fois dans votre programme. Au contraire, le code dune fonction nexiste quen un seul exemplaire. En ce qui concerne lencombrement, la palme revient donc la fonction. En revanche, chaque appel de fonction est associ un certain overhead (surcharge) de temps CPU, caus par le mcanisme de liaison et de passage des arguments dune part et par le renvoi du rsultat dautre part. Ce nest pas le cas pour une macro, puisquil ny a pas dappel, son expansion tant directement insre dans le code. Ici, cest donc la macro qui est sur la plus haute marche du podium. Pour le programmeur dbutant, ces considrations sont, en gnral, peu importantes. Elles ne deviennent proccupantes que lorsque lon sattaque de gros programmes ou des programmes dont la vitesse dexcution ou lencombrement en mmoire est crucial.

Comment examiner lexpansion dune macro


Il y a des moments o vous aimeriez pouvoir contempler ce que le prprocesseur a fait lors de lexpansion dune macro, ne serait-ce que pour comprendre pourquoi elle ne se comporte pas comme vous lespriez. Pour cela, il faut demander au compilateur de crer un chier contenant le rsultat du traitement par le prprocesseur ou appeler directement celui-ci. Cela dpend du compilateur que vous utilisez. En mode ligne de commande, cependant, on peut appeler le prprocesseur de la faon suivante :
cpp program.c

Selon le prprocesseur, le rsultat pourra tre afch directement lcran ou mis dans un chier ayant lextension .i et dans lequel vous trouverez lexpansion de votre code prcde de celle des chiers dinclude, ce qui peut conduire un chier assez gros. Cest vers la n que se trouve ce qui dcoule directement de vos propres instructions. Il ne vous reste plus qu charger le chier obtenu dans un diteur de texte pour lexaminer loisir.

http://fribok.blogspot.com/

eils Cons

faire Utiliser #define pour dnir des constantes symboliques qui rendent les programmes plus faciles lire et maintenir. Vous pouvez ainsi dnir des couleurs, les mots OUI, NON, VRAI et FAUX, (pour un test, par exemple), TOUJOURS et JAMAIS (pour un while, par exemple). ne pas faire Abuser des macros "fonctions". Tant que vous naurez pas une bonne exprience du C, vous risquez davoir des surprises !

La directive #include
Dans tous les chapitres qui prcdent, vous avez fait usage de la directive #include pour inclure des chiers den-tte au dbut de votre programme. Lorsquil rencontre cette directive, le prprocesseur lit le chier spci et linsre dans un chier intermdiaire (celui quil passera plus tard au compilateur) lemplacement o se trouvait linclude. Il nest pas possible dutiliser des caractres de remplacement (* ou ?) dans un nom de chier dinclude. Dailleurs, cela naurait aucun sens. Vous pouvez imbriquer des inclusions de chiers. Rien nempche un chier "inclus" de contenir lui-mme un #include dun chier qui, son tour, contiendrait... Il y a deux faons de spcier le nom du chier inclure. Vous le placez soit entre les caractres < et >, soit entre guillemets. Ce choix nest pas indiffrent. Dans le premier cas, le prprocesseur va rechercher le chier inclure dans les rpertoires standard des chiers dinclude. Sil ne le trouve pas, il consultera le rpertoire courant. "Quest-ce que les rpertoires standard ?" vous demandez-vous peut-tre. Il sagit dune liste de rpertoires par dfaut qui dpend de votre systme (gnralement /usr/include sur un systme Unix ou Linux) et qui peut tre tendue si vous utilisez loption -I dun compilateur en ligne de commande comme cc ou gcc. Par exemple, si vous compilez en indiquant I/usr/local/include votre compilateur gcc, les rpertoires standard seront /usr/include et /usr/local/include. La seconde mthode pour spcier un chier dinclude est de placer son nom entre guillemets comme dans #include "monfic.h". Dans ce cas, le prprocesseur ira chercher le chier dans le rpertoire contenant le chier source compiler puis dans les rpertoires standard. En rgle gnrale, les chiers den-tte que vous avez crit vous-mme doivent tre placs dans le mme rpertoire que les chiers sources. Les rpertoires standard sont rservs pour les chiers den-tte de bibliothques.

http://fribok.blogspot.com/

#if , #elif, #else et #endif


Ces quatre directives gouvernent ce quon appelle une compilation conditionnelle. Cette expression signie que certains blocs de programme ne seront compils que si une certaine condition est remplie. La directive #if et ses surs ressemblent aux instructions if, else, etc. Mais ces dernires contrlent lexcution du programme alors que les directives en contrlent la compilation. La structure dun bloc #if est la suivante :
#if condition_l Bloc dinstructions #elif condition_2 Bloc dinstructions ... #elif condition_n Bloc dinstructions #else Bloc dinstructions #endif 1 2

n par dfaut

Lexpression de test quutilise #if peut tre nimporte quelle expression dont la valeur peut se rduire une constante. Lusage de loprateur sizeof(), de la coercition ou du type float est interdit. En gnral, on utilise des constantes symboliques cres au moyen de la directive #define. Chaque Bloc dinstructions consiste en une ou plusieurs instructions C de nimporte quel type, y compris des directives du prprocesseur. Elles nont pas besoin dtre imbriques entre des accolades, mais ce nest pas dfendu. Les directives #if et #endif sont ncessaires, mais #else et #elif sont facultatives. Vous pouvez placer autant de directives #elif que vous le voulez, mais une seule #else. Lorsque le compilateur atteint un #if il teste la condition associe. Si cette condition a la valeur VRAI (non zro), les instructions qui suivent sont compiles. Si elle a la valeur FAUX (zro), le compilateur teste, dans lordre, les conditions associes chacune des #elif qui suivent. Les instructions qui suivent la premire directive #elif dont la valeur teste est VRAI sont compiles. Si aucune des conditions ne vaut VRAI, les instructions suivant la directive #else sont compiles. Au plus, un seul bloc dinstructions encadr entre un #if et un #endif est compil. Si le compilateur ne trouve pas de directive #else, aucune instruction ne sera compile. Lemploi de ce mcanisme de compilation conditionnelle nest limit que par votre imagination. En voici un exemple. Supposez que vous criviez un programme utilisant des donnes dpendant dun systme dexploitation ( cause de fonctions non portables, par exemple), vous pouvez utiliser une batterie de #if...#endif pour oprer une slection parmi plusieurs chiers den-tte :

http://fribok.blogspot.com/

#if SOLARIS == 1 #include "solaris.h" #elif LINUX == 1 #include "linux.h" #elif WINDOWS == 1 #include "windows.h" #else #include "generic.h" #endif

Utilisation de #if...#endif pour la mise au point


Une autre utilisation frquente de la construction #if...#endif est linclusion dinstructions de mise au point dans le programme. Vous pouvez donner une constante symbolique DEBUG la valeur 0 ou la valeur 1 et, des endroits choisis du programme, insrer des instructions conditionnelles :
#if DEBUG == 1 ... instructions de mise au point ... #endif

Au cours de la mise au point du programme, DEBUG aura la valeur 1 et la n, on refera une compilation aprs lui avoir donn la valeur 0, "effaant" ainsi les instructions de mise au point. On peut utiliser loprateur defined pour tester si une constante symbolique a t ou non dnie. Ainsi, lexpression :
defined(NOM)

prend la valeur VRAI si NOM a t dni (par une directive #define), et FAUX dans le cas contraire. Peu importe la valeur qui lui a t donne. Il nest mme pas ncessaire de xer une valeur, il suft dcrire, par exemple :
#define NOM

On peut alors rcrire le prcdent exemple sous la forme :


#if defined(NOM) ... instructions de mise au point ... #endif

On peut aussi utiliser defined() pour assigner une dnition un nom, seulement si ce nom na pas encore fait lobjet dun #define:
#if! defined(MACHIN)/* si MACHIN na jamais t dfini */ #define MACHIN 23 #endif

http://fribok.blogspot.com/

#ifdef, #ifndef
Ces deux instructions sont quivalentes #if defined et #if ! defined. Nous vous les donnons pour vous permettre de comprendre plus facilement certains programmes qui les utilisent. Elles sont parfois prfrables car plus courtes crire. Nanmoins, elles sont limites car vous ne pouvez pas tester plusieurs conditions la fois, ni utiliser de #elif ou de #else. Nous vous prsentons un exemple ci-dessous.

Comment viter plusieurs inclusions dun chier den-tte


Lorsquun programme grossit ou que vous employez des chiers den-tte de plus en plus nombreux, vous courez le risque den inclure un plusieurs fois, ce qui pourrait poser des problmes au compilateur. Avec ce que nous venons de voir, il est facile dviter ce problme (voir Listing 21.5). Listing 21.5 : Utilisation des directives du prprocesseur avec des chiers den-tte
1:/* prog.hprog.h - Fichier den-tte comportant un test 2:destin empcher plusieurs inclusions */ 3:#ifndef PROG_H 4:/* le fichier na pas encore t inclus */ 5:#define PROG_H 6: 7:/* Informations du fichier den-tte */ 8: 9: #endif /* fin de prog.h */

Analyse la ligne 3, on regarde si PROG H est dni. Ce nom a t choisi pour permettre de reprer le chier quil concerne (prog.h), mais on aurait pu aussi bien choisir TOTO. Sil est dni, on ne fait rien du tout. Si PROG H ne lest pas, alors on le dnit (ligne 5) et on "excute" le contenu du chier den-tte (lignes 6 8).

La directive #undef
De mme quon peut dnir un nom laide dune directive #define, on peut annuler cette dnition par une directive #undef. En voici un exemple :
#define DEBUG 1 /* Dans cette section du programme, toutes les occurrences de DEBUG seront remplaces par 1 et lexpression defined(DEBUG) vaudra VRAI.

http://fribok.blogspot.com/

*/ #undef DEBUG /* Dans cette section du programme, toutes les occurrences de DEBUG seront remplaces par 0 et lexpression defined(DEBUG) vaudra FAUX. */

Grce #define et #undef, on peut donner un mme nom une valeur changeante dans un mme programme.

Macros prdnies
La plupart des compilateurs contiennent un certain nombre de macros prdnies. Les plus utilises sont DATE , TIME , LINE et FILE . Remarquez que ces noms sont prcds et suivis par deux blancs souligns. Cela an de rendre peu probable lexistence de macros de mme nom accidentellement dnies par le programmeur. ce sujet, sachez quil est dconseill aux programmeurs de nommer leurs constantes symboliques ou macros avec des noms commenant par un (ou deux) blanc(s) soulign(s). Elles sont rserves aux constantes prdnies du langage C et certaines constantes de bibliothques standard comme libc. Ces macros fonctionnent comme les macros de substitution que nous avons rencontres au dbut de ce chapitre : le prprocesseur remplace ces noms par les chanes de caractres appropries : date, heure, numro de linstruction dans le programme (ici, ce nest pas une chane, mais une valeur dcimale int) et nom du chier contenant cette macro. On peut ainsi facilement afcher la date laquelle a t compil un module ou le numro de ligne dune instruction ayant caus un incident. Voici un exemple simple dutilisation de ces macros :
31: 32:printf("Programme%s: Fichier non trouv ligne%d\n", __FILE__, __LINE__); 33:

On obtiendra un afchage de ce genre :


Programme toto.c: Fichier non trouv la ligne32.

Cela peut vous paratre peu important, mais vous risquez den percevoir plus nettement lintrt quand vos programmes seront devenus assez importants.

http://fribok.blogspot.com/

eils Cons

faire Utiliser les macros plus prcis. FILE et LINE pour rendre les messages derreur

Placer des parenthses autour de la valeur passe une macro an dviter tout effet de bord fcheux. ne pas faire Oublier le #endif la suite dun #if.

Les arguments de la ligne de commande


Tout programme C peut accder aux arguments qui lui ont t passs sur sa ligne de commande, cest--dire au