Vous êtes sur la page 1sur 94

rieure Ecole Nationale Supe es de Techniques Avance

Programmation en C

Pierre-Alain Fouque et David Pointcheval


E-mail : Pierre-Alain.Fouque@ens.fr Web : http://www.di.ens.fr/~fouque/

Table des mati` eres


1 Introduction 1.1 Lordinateur . . . . . . . . . . . . . . . . . . . 1.2 Programmer en C . . . . . . . . . . . . . . . . 1.2.1 G en eralit es . . . . . . . . . . . . . . . 1.2.2 Un editeur de texte : emacs . . . . . . 1.2.3 Analyse du programme . . . . . . . . . 1.2.4 Un compilateur C : gcc . . . . . . . . 1.3 Quelques g en eralit es sur la syntaxe du langage 1.3.1 Mise en page et indentation . . . . . . 1.3.2 Les identicateurs . . . . . . . . . . . . 1.3.3 Les instructions . . . . . . . . . . . . . 1.3.4 Organisation dun programme C . . . . 11 11 12 12 12 15 16 17 17 17 17 18 21 21 22 22 22 23 23 23 24 24 24 25 27 27 28 28 29 30 30 30 31 31

. . . . . . . . . . . . C . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

2 Les types 2.1 Les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Les types de base . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Les types entiers (int, short int, long int et long 2.2.2 Les types ottants (float, double et long double) . 2.2.3 Le type caract` ere (char) . . . . . . . . . . . . . . . . 2.3 Les types structur es . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Les tableaux . . . . . . . . . . . . . . . . . . . . . . . 2.3.2 Les tableaux ` a plusieurs dimensions . . . . . . . . . . 2.3.3 Les structures . . . . . . . . . . . . . . . . . . . . . . 2.4 Les pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Nouveaux types . . . . . . . . . . . . . . . . . . . . . . . . . 3 Les variables et les constantes 3.1 D eclaration des variables . . . . . . . . . . . 3.1.1 D eclaration des types simples . . . . 3.1.2 D eclaration des tableaux et pointeurs 3.1.3 D eclaration des objets complexes . . 3.2 Initialisation des variables . . . . . . . . . . 3.3 Constantes . . . . . . . . . . . . . . . . . . . 3.3.1 Types simples . . . . . . . . . . . . . 3.3.2 Types complexes . . . . . . . . . . . 3.4 Dur ee de vie et visibilit e des variables . . . .

. . . . . . long . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . int) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

` TABLE DES MATIERES

4 Les entr ees-sorties 4.1 Lachage avec printf . . . . 4.1.1 Simple achage . . . . 4.1.2 Formattage des sorties 4.2 La saisie avec scanf . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

35 35 35 36 37 39 39 40 42 42 43 43 43 43 44 44 45 45 45 46 46 48 49 49 50 50 50 50 50 51 53 53 54 54 54 55 56 56 58 58 59 61 61 62

5 Les op erateurs et les expressions 5.1 Les op erateurs . . . . . . . . . . . . . . . . . . . . 5.1.1 Les op erateurs arithm etiques . . . . . . . . 5.1.2 Op erateur de conversion de type ( cast ) 5.1.3 Op erateur de taille . . . . . . . . . . . . . 5.1.4 Op erateurs logiques . . . . . . . . . . . . . 5.1.5 Op erateurs de masquage . . . . . . . . . . 5.1.6 Op erateurs de relations . . . . . . . . . . . 5.1.7 Op erateur daectation . . . . . . . . . . . 5.1.8 Op erateurs abr eg es . . . . . . . . . . . . . 5.2 Les expressions . . . . . . . . . . . . . . . . . . . 6 Les structures de contr ole 6.1 Instruction . . . . . . . . . . . 6.2 Les boucles . . . . . . . . . . 6.2.1 Les boucles while . . . 6.2.2 Les boucles for . . . . 6.2.3 Les boucles do while . 6.3 Les conditions . . . . . . . . . 6.3.1 Condition if . . . . . 6.3.2 Condition switch . . . 6.4 Sauts Inconditionnels . . . . . 6.4.1 break . . . . . . . . . 6.4.2 continue . . . . . . . 6.4.3 return . . . . . . . . . 6.4.4 goto . . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

7 Programme Structur e 7.1 Les fonctions . . . . . . . . . . . 7.1.1 D eclaration dune fonction 7.1.2 Corps de la fonction . . . 7.1.3 Retour de la r eponse . . . 7.1.4 Arguments dune fonction 7.1.5 Fonction main . . . . . . . 7.2 R ecursivit e . . . . . . . . . . . . 7.3 Les modules . . . . . . . . . . . . 7.3.1 Structure . . . . . . . . . 7.3.2 Compilation . . . . . . . . 7.4 Le pr eprocesseur . . . . . . . . . 7.4.1 Inclusions et d enitions . . 7.4.2 Compilation conditionnelle

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

` TABLE DES MATIERES

7.4.3

Le pr eprocesseur gcc . . . . . . . . . . . . . . . . . . . . . . . . . . 62 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 65 65 66 66 67 67 68 71 71 72 72 72 73 75 76 76 77 77 78 78 80 80 80 80 81 81 81 82 82 82 85 85 85 85 88 88 88 89 89 89 89 90

8 Les pointeurs, les tableaux et les structures 8.1 Pointeurs . . . . . . . . . . . . . . . . . . . 8.1.1 D enition . . . . . . . . . . . . . . . 8.1.2 Utilisation . . . . . . . . . . . . . . . 8.1.3 Passage par adresse . . . . . . . . . . 8.2 Tableaux . . . . . . . . . . . . . . . . . . . . 8.3 Allocation dynamique de m emoire . . . . . . 8.4 Les structures . . . . . . . . . . . . . . . . . 9 Les 9.1 9.2 9.3 structures dynamiques Structure de liste . . . . . . . . . . Impl ementation des listes cha n ees . Extensions . . . . . . . . . . . . . . 9.3.1 Listes doublement cha n ees . 9.3.2 Arbres . . . . . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

10 Lenvironnement sous UNIX 10.1 Une construction sur mesure : make . . . . . 10.1.1 Fichier de Conguration : Makefile . 10.1.2 Wildcards et D ependances . . . . . . 10.1.3 Constantes et Variables . . . . . . . . 10.1.4 Cibles Fictives . . . . . . . . . . . . . 10.1.5 Invocation de la Commande make . . 10.2 Une gestion des versions : cvs . . . . . . . . 10.2.1 Cr eation dun projet . . . . . . . . . 10.2.2 Fichier dinformation . . . . . . . . . 10.2.3 Modications de la structure . . . . . 10.2.4 Int egration des modications . . . . 10.2.5 Gestion des versions . . . . . . . . . 10.2.6 Commentaires . . . . . . . . . . . . . 10.3 Le d ebogueur : gdb . . . . . . . . . . . . . . 10.3.1 Lancement du d ebogueur . . . . . . . 10.3.2 Commandes de base . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

11 Quelques compl ements 11.1 Les cha nes de caract` eres . . . . . . . . . . . . 11.1.1 Structure dune cha ne de caract` eres . 11.1.2 Quelques commandes sur les cha nes de 11.2 Gestion des chiers . . . . . . . . . . . . . . . 11.2.1 Type chier . . . . . . . . . . . . . . . 11.2.2 Cr eation dun chier . . . . . . . . . . 11.2.3 Lecture/Ecriture . . . . . . . . . . . . 11.2.4 Fin de chier . . . . . . . . . . . . . . 11.2.5 Cl oture . . . . . . . . . . . . . . . . . 11.3 C 99 . . . . . . . . . . . . . . . . . . . . . . . 11.4 La biblioth` eque standard . . . . . . . . . . . .

. . . . . . . . . . . . caract` eres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

` TABLE DES MATIERES

Liste des Programmes


1 Introduction 11 1 Hello World (hello.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2 Programme g en erique (generique.c) . . . . . . . . . . . . . . . . . . . . . 19 2 Les 3 4 5 types 21 Tableaux (tableaux.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Structure (structure.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Typedef (typedef.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3 Les variables et les constantes 27 6 Variables (variables.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 7 Variables annexe (options.c) . . . . . . . . . . . . . . . . . . . . . . . . 33 4 Les entr ees-sorties 35 8 Entr ees/Sorties (io.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 5 Les op erateurs et les expressions 39 9 Op erateurs arithm etiques (arithmetique.c) . . . . . . . . . . . . . . . . . 40 6 Les 10 11 12 13 14 structures de contr ole PGCD (pgcd.c) . . . . . Carr es (carres.c) . . . Binaire (binaire.c) . . Parit e (parite.c) . . . . Valeur (valeur.c) . . . 45 46 47 48 49 51 53 55 57 58 59 60 60

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

7 Programme Structur e 15 Incr ementation (incrementation.c) . . . . . . 16 Factorielle (fact.c) . . . . . . . . . . . . . . . . 17 Fibonacci (fibo.c) . . . . . . . . . . . . . . . . 18 D eclaration des types et fonctions (complexe.h) 19 D enition des fonctions (complexe.c) . . . . . . 20 Module principal (complexe-main.c) . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

8 Les pointeurs, les tableaux et les structures 65 21 Auto-Incr ementation (auto-incrementation.c) . . . . . . . . . . . . . . . 66 22 Suite de Fibonacci tableau (fibo-tableau.c) . . . . . . . . . . . . . . . 69

LISTE DES PROGRAMMES

9 Les structures dynamiques 71 23 Listes cha n ees (liste.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 10 Lenvironnement sous UNIX 24 Exemple de chier Makefile (Makefile1) 25 Makele : version compacte (Makefile2) . 26 Makele : classique C (Makefile3) . . . . 27 D ebordement (segmentation.c) . . . . . 11 Quelques compl ements 28 Palindrome (palindrome.c) . . . . . 29 Tableau vs. Pointeur (tblvsptr.c) . 30 Tableau vs. Pointeur (tblvsptr1.c) 31 Gestion des chiers (copie.c) . . . . 32 Erreurs dans la biblioth` eque standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 77 78 79 83 85 86 87 88 91 92

. . . . . . . . . . . . . . . . . . . . . . . . . . . . (perror.c)

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

Table des gures

1 Introduction 1.1 Organisation dun ordinateur Programmation en 1.2 Les etapes de la programmation . . . . . . . . . . 1.3 Raccourcis-clavier sous emacs . . . . . . . . . . . 1.4 Options du compilateur gcc . . . . . . . . . . . .

C . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

11 12 13 14 16

2 Les types 21 2.1 Types entiers sous GCC/Linux . . . . . . . . . . . . . . . . . . . . . . . . 22 2.2 Types ottants sous GCC/Linux . . . . . . . . . . . . . . . . . . . . . . . 23 3 Les variables et les constantes 27 3.1 D eclaration des tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.2 D eclaration des structures . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4 Les entr ees-sorties 35 4.1 Achage des variables avec printf . . . . . . . . . . . . . . . . . . . . . . 37 4.2 Saisie avec scanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 5 Les 5.1 5.2 5.3 5.4 op erateurs et les expressions Op erateurs unaires . . . . . . . Op erateurs binaires . . . . . . Cast automatique . . . . . . . Op erateurs abr eg es . . . . . . . 39 41 41 42 44 45 53

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

6 Les structures de contr ole 7 Programme Structur e

8 Les pointeurs, les tableaux et les structures 65 8.1 Tableau dentiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

TABLE DES FIGURES

9 Les 9.1 9.2 9.3

structures dynamiques Liste cha n ee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Liste doublement cha n ee . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arbres binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

71 71 72 73 75 85

10 Lenvironnement sous UNIX 11 Quelques compl ements

Avant-Propos
Ce document regroupe lessentiel pour g erer un (gros) projet en C sous un environnement de type UNIX. Mais avant tout, ` a quoi sert un langage de programmation, tel que le langage C, ` a lheure o` u les ordinateurs ob eissent ` a la voix de leur ma tre ? Un ordinateur pr esente une capacit e de calcul enorme. En eet, les machines actuelles atteignent ou d epassent all` egrement le milliard dinstructions ` a la seconde, permettant ainsi deectuer des t aches r ep etitives ou a priori longues et fastidieuses, ais ement et rapidement. Cependant, le langage naturel de lordinateur (dit langage machine ) est dicilement compr ehensible par lhomme. Dun autre c ot e, le langage naturel de lhomme est souvent ambigu, plein de sous-entendus, et donc dicile ` a interpr eter par une machine. Le langage C, comme tout langage de programmation, est un moyen de communication avec lordinateur, plus abordable. En eet, un interpr` ete, le compilateur, va se charger de traduire votre programme C (dit chier source ) en langage machine (votre ex ecutable ). Il ne faut donc pas perdre de vue que votre programme servira ` a commander . . .un ordinateur, donc sans imagination ni bonne volont e. Les ordres devront alors etre clairs, nets et pr ecis, et surtout sans ambigu t e. Ainsi, certaines r` egles doivent-elles etre respect ees. Ce document tente de recenser les r` egles essentielles, mais aussi les outils mis ` a votre disposition pour vous aider ` a mener ` a bien un projet important. Remarque : ce cours ne se pr etend pas etre un document exhaustif en la mati` ere, mais souhaite apporter, ` a un programmeur d ebutant, les bases de la programmation en C, et plus sp eciquement avec gcc sous Linux. Ainsi, la fonction man est dune aide pr ecieuse. En eet, la page 3 du man contient la description de toutes les fonctions C : > man 3 printf donne le prototype de toutes les fonctions li ees au formattage de sortie. De plus, ce document ne suit pas le cours magistral, mais tente plut ot de regrouper sous un m eme chapitre les objets de m eme type, en se concentrant sur lessentiel. Aussi, certaines omissions sont volontaires pour eviter les confusions, ainsi que lutilisation dastuces tr` es sp eciques au langage C. En eet, le langage C permet beaucoup de libert e, en comparaison au Pascal par exemple. Ce document est un peu plus strict, an de permettre un passage plus ais e, ult erieurement, ` a un autre langage (tel le langage JAVA). Pour toute information : E-mail : Pierre-Alain.Fouque@ens.fr Web : http://www.di.ens.fr/~fouque/ Cours : http://www.di.ens.fr/~fouque/enseignement/ensta/

10

TABLE DES FIGURES

Chapitre 1 Introduction
Sommaire
1.1 1.2 Lordinateur . . . . . . . . . . . . . . . . . . . . . . Programmer en C . . . . . . . . . . . . . . . . . . . 1.2.1 G en eralit es . . . . . . . . . . . . . . . . . . . . . . 1.2.2 Un editeur de texte : emacs . . . . . . . . . . . . . 1.2.3 Analyse du programme . . . . . . . . . . . . . . . 1.2.3.1 Les fonctions . . . . . . . . . . . . . . . . 1.2.3.2 Les commentaires . . . . . . . . . . . . . 1.2.3.3 Le pr eprocesseur . . . . . . . . . . . . . . 1.2.4 Un compilateur C : gcc . . . . . . . . . . . . . . . 1.3 Quelques g en eralit es sur la syntaxe du langage C 1.3.1 Mise en page et indentation . . . . . . . . . . . . . 1.3.2 Les identicateurs . . . . . . . . . . . . . . . . . . 1.3.3 Les instructions . . . . . . . . . . . . . . . . . . . . 1.3.4 Organisation dun programme C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 12 12 12 15 15 15 16 16 17 17 17 17 18

Comme nous venons de le voir, un langage de programmation sert de moyen de communication avec un ordinateur, qui ne comprend que le langage machine, par le biais dun compilateur. Nous allons donc, dans un premier temps voir les parties essentielles dun ordinateur. Ensuite, pour entrer progressivement dans le vif du sujet, nous essaierons un premier petit programme, an de xer les diverses etapes de l edition et de la compilation.

1.1

Lordinateur

Un ordinateur est constitu e dun processeur (CPU, pour Central Processor Unit) reli e aux di erents composants : la m emoire centrale (ou m emoire vive) et la m emoire de masse (disque dur), ainsi que les p eriph eriques dentr ee-sortie, le clavier et l ecran (voir gure 1.1). La m emoire de masse sert ` a stocker des informations ` a long terme (m eme lorsque lordinateur nest plus sous tension), tandis que la m emoire vive stocke les informations

12

CHAPITRE 1. INTRODUCTION

compilation + dition liens

toto.c toto Disque Dur sauvegarde

saisie toto
excutable

Mmoire

Mon beau programme en C tap sur le clavier, affich lcran !...

variables

CPU

Fig. 1.1 Organisation dun ordinateur Programmation en C

n ecessaires ` a la bonne ex ecution dune t ache ponctuelle : le programme (la liste des instructions ` a ex ecuter), les variables, etc. Les informations stock ees en m emoire vive seront perdues ` a lextinction de lordinateur. Lutilisateur dialogue avec lordinateur par linterm ediaire du clavier (entr ee standard) et de l ecran (sortie standard).

1.2
1.2.1

Programmer en C
G en eralit es

Lutilisateur tape son programme en langage C, avec un editeur de texte, et sauvegarde le chier source sur le disque dur. An de le rendre compr ehensible par lordinateur, il le compile en langage machine, avec un compilateur C, puis edite les liens, produisant ainsi une version ex ecutable. Le programme ex ecutable peut alors etre envoy e au processeur : lex ecutable est charg e en m emoire centrale. Le processeur ex ecute alors lensemble des instructions, utilisant la m emoire centrale pour stocker ses calculs temporaires. Pour comprendre toutes ces etapes, d ecrites plus loin plus en d etail, consid erons notre premier programme, le classique Hello World ! ! (voir programme 1). Il faut tout dabord le saisir au clavier, le compiler (pr eprocesseur, assembleur puis optimiseur de code), editer les liens, puis lex ecuter (voir gure 1.2).

1.2.2

Un editeur de texte : emacs

La premi` ere etape consiste ` a saisir et ` a sauvegarder le programme source hello.c. Pour cela, nous utiliserons l editeur de texte bien connu emacs : ` a linvite du shell, on tape

1.2. PROGRAMMER EN C

13

hello.c /* Mon premier programme en C */ #include <stdio.h> int main () { printf("Hello World !!\n"); return 0; }

Programme 1: Hello World (hello.c)

Saisie
hello.c tata.c titi.c toto.c

fichiers source fichiers objet fichier excutable

Compilation
hello.o tata.o titi.o toto.o

dition des liens


hello a.out

Fig. 1.2 Les etapes de la programmation

> emacs hello.c & Le & en n de ligne permettant de r ecup erer la main dans le shell apr` es avoir lanc e l editeur, an de pouvoir compiler, sans quitter l edition en cours, qui sera sans doute encore n ecessaire pour la correction des erreurs rep er ees par le compilateur (ne vous aolez pas, une compilation marche rarement du premier coup !). Les inconditionnels de vi ou vim, kate, ou eclipse ou de tout autre editeur pourront garder leurs habitudes. Cependant, emacs comme dautres editeurs, a de nombreux avantages lors de la programmation : il poss` ede un mode C qui indente au fur et ` a mesure de la saisie. Cela clarie la lecture, mais aussi permet de d etecter les erreurs classiques que nous verrons plus loin (oubli daccolades, de parenth` eses, de points-virgules, etc). De plus, emacs est un editeur tr` es puissant et tr` es pratique. Il peut manipuler plusieurs chiers ` a la fois dans di erents buers , sans lancer plusieurs emacs en parall` ele (voir le menu d eroulant buer pour la liste des chiers ouverts). Enn, il ore une interface conviviale au d ebogueur (voir la section 10.3). Les commandes essentielles peuvent etre trouv ees dans les menus d eroulants, mais des raccourcis-clavier existent (voir gure 1.3) qui permettent de limiter lusage de la souris.

14

CHAPITRE 1. INTRODUCTION

Fichier Ctrl-x Ctrl-f Ctrl-x Ctrl-s Ctrl-x Ctrl-w Buer Ctrl-x Ctrl-b Ctrl-x b Ctrl-x k Ctrl-x 2 Ctrl-x 3 Ctrl-x 1 Ctrl-x Ctrl-w D eplacement Ctrl-a Ctrl-e D ebut Fin Edition Ctrl-<SPC> Ctrl-w Alt-w Ctrl-y CtrlDivers Ctrl-g Ctrl-x Ctrl-c

ouvrir un chier sauver le chier sous le nom courant sauver le chier sous un nouveau nom acher la liste des buers ouverts changer de buer courant fermer un buer couper la fen etre en 2, verticalement couper la fen etre en 2, horizontalement une seule fen etre sauver le chier sous un nouveau nom d ebut de ligne n de ligne d ebut du chier n du chier marquer un d ebut de bloc couper du d ebut du bloc jusqu` a la position actuelle copier du d ebut du bloc jusqu` a la position actuelle coller le bloc copi e ou coup e annuler la derni` ere commande (puis les pr ec edentes, etc) annuler toute commande en cours tout dialogue dans le mini-buer fermer tous les buers et quitter

Fig. 1.3 Raccourcis-clavier sous emacs

1.2. PROGRAMMER EN C

15

1.2.3

Analyse du programme

Avant de lancer la compilation, analysons bri` evement ces quelques lignes. Tout dabord, hello.c est le nom du chier source. Un programme est une liste de fonctions. Le programme en question nen contient quune seule, appel ee main, en raison de sa simplicit e. Mais d` es quun programme se complique, il ne faut pas h esiter ` a multiplier les fonctions. 1.2.3.1 Les fonctions

int main() est len-t ete de la fonction, dont le corps est d ecrit entre les accolades qui suivent. Comme lindique son nom, la fonction main est la fonction principale, la seule ` a etre appel ee lors de lex ecution du programme. Cest donc ` a elle de distribuer les t aches, si de multiples t aches doivent etre eectu ees. Il ne sagit pas pour autant de surcharger le corps de cette fonction. En eet, il est conseill e d ecrire des fonctions sp eciques pour chaque t ache et sous-t ache, ces fonctions pouvant alors etre appel ees les unes par les autres, et par la fonction main en particulier, voire sappeler elles-m emes lors de fonctions dites r ecursives . Nous verrons cela plus en d etail dans le chapitre 7. Ce programme etant tr` es simple, nous navons pas multipli e les fonctions, mais il faut garder ` a lesprit que plus les fonctions seront simples et courtes, plus elles auront de chance d etre correctes. Len-t ete dune fonction (ou prototype ) d ecrit ses caract eristiques, vues de lext erieur : entre parenth` eses, on liste les arguments que la fonction prend en entr ee, avec leur type. La fonction main ne prend aucun argument, do` u les parenth` eses vides () ; ` a la gauche de len-t ete, est pr ecis e le type de sortie de la fonction. Pour la fonction main, il sagit dun entier retourn e au shell appelant, correspondant au code derreur (0, lorsque tout sest bien pass e, une autre valeur signie une erreur). Le corps dune fonction d ecrit le mode op eratoire, ce que doit faire la fonction. Pour ce qui est de la fonction main etudi ee, le corps est en eet el ementaire : la ligne printf("Hello World !!\n"); ache ` a l ecran la cha ne de caract` eres entre guillemets. Le \n correspond ` a un saut de ligne. nalement, la ligne return 0; conclut la fonction, retournant lentier de sortie de la fonction, le code derreur 0 signiant que tout sest bien pass e. 1.2.3.2 Les commentaires

Un programme ecrit un jour sera peut- etre relu ou utilis e ensuite par quelquun dautre, ou par vous-m eme dans quelques ann ees. Sans commentaires sur le pourquoi et le comment de ceci et de cela, la lecture sera ardue. Ainsi est-il conseill e dajouter des commentaires dans vos programmes. Ils ne surchargeront pas lex ecutable ni ne ralentiront son ex ecution : les commentaires sont supprim es ` a la compilation. La ligne /* Mon premier programme en C */ , comme tout texte entre /* et */ est un commentaire.

16

CHAPITRE 1. INTRODUCTION

1.2.3.3

Le pr eprocesseur

La ligne #include <stdio.h> est interpr et ee par le pr eprocesseur. Il ins` ere alors le chier stdio.h ` a cet emplacement avant denvoyer le programme au compilateur. Ce chier contient les en-t etes des fonctions usuelles pour les entr ees-sorties (STanDard Input-Output), telle que printf. De nombreuses directives peuvent etre ainsi donn ees au pr eprocesseur, telles que des insertions conditionnelles, des macros, etc. Toutes ces directives apparaissent imp erativement en d ebut de ligne (donc une seule par ligne), en commen cant par un #.

1.2.4

Un compilateur C : gcc

An de traduire le programme C en langage machine, on fait appel ` a un compilateur. Nous utiliserons gcc (pour GNU C Compiler). Un tel compilateur eectue en fait plusieurs t aches successives : le pr eprocesseur, qui, comme on la d ej` a vu ci-dessus, interpr` ete quelques commandes el ementaires pour compl eter et mettre en forme le chier source ; le compilateur, en tant que tel, qui traduit le chier source en code assembleur, un langage tr` es proche du langage machine ; loptimiseur de code, qui remplace certaines s equences dinstructions par dautres plus ecaces, d eroule certaines boucles, supprime certains sauts, etc. Loptimisation est tr` es sp ecique aux caract eristiques du processeur ; lassembleur, qui traduit le code assembleur en langage machine. On obtient alors le chier objet ; l editeur de liens, qui interface les di erents chiers objets entre eux, mais egalement avec les biblioth` eques usuelles fournies avec la distribution classique du C. En g en eral, toutes ces op erations sont eectu ees en une seule etape, transparente pour lutilisateur (avec gcc hello.c). On obtient alors un ex ecutable d enomm e a.out, que lon peut ex ecuter depuis le shell : > gcc hello.c > a.out -E lance le pr eprocesseur (mais neectue aucune compilation) > gcc -E hello.c retourne le r esultat sur la sortie standard -S cr eation du chier assembleur (avant l edition des liens) > gcc -S hello.c produit hello.s -c cr eation du module objet (avant l edition des liens) > gcc -c hello.c produit hello.o -O2/-O3 optimisation du code -o <output> permet de sp ecier le nom du chier cr e e -v mode verbose qui explique tout ce quil fait -Wall compilation exigeante , informant des erreurs b enignes Fig. 1.4 Options du compilateur gcc Diverses options peuvent etre utilis ees lors de la compilation (voir gure 1.4), notamment pour contr oler les phases de la compilation que lon veut eectuer. Les plus utiles

ERALIT SUR LA SYNTAXE DU LANGAGE C ES 1.3. QUELQUES GEN

17

etant -c lors dun projet faisant intervenir plusieurs modules qui n ecessitent des compilations s epar ees, et -o qui permet de pr eciser le nom du chier ex ecutable (d enomm e par d efaut a.out). Loption -Wall est egalement tr` es utile car elle demande au compilateur dinformer lutilisateur de toute anomalie dans le source. Il sagit souvent derreurs dinadvertences, non fatales ` a la compilation, mais qui rendent lex ecution parfois incorrecte.

1.3
1.3.1

Quelques g en eralit es sur la syntaxe du langage C


Mise en page et indentation

Un programme C peut etre ecrit tr` es librement, ` a lexception des directives envoy ees au pr eprocesseur qui commencent n ecessairement par un # et en d ebut de ligne (et donc ` une seule directive par ligne). A part cela, les sauts de lignes et les espaces multiples ne sont pas signicatifs pour le compilateur. Reste maintenant ` a ecrire un programme qui aide ` a la compr ehension, et notamment au d eboguage. Pour cela, l editeur de texte emacs est dun pr ecieux recours. En eet, il aide ` a indenter correctement (et peut m eme colorer les di erentes mots selon leur caract eristique). Si cela nest pas automatique, taper Alt-x c-mode (pour passer dans un environnement C) Alt-x global-font-lock-mode (pour passer en mode color e) Il est alors fortement conseill e de respecter les r` egles dindentation : d ecaler dun cran (ex : trois espaces) vers la droite tout bloc inclus dans un pr ec edent. On peut ainsi mieux rep erer qui d epend de quoi, et si tous les blocs ouverts ont bien et e ferm es.

1.3.2

Les identicateurs

Les noms de variables, de constantes ou de fonctions sont compos es de caract` eres au choix parmi les lettres a-z et A-Z, et les chires 0-9, avec la possibilit e dutiliser le symbole _ (par exemple, pour remplacer lespace). Cependant, ces noms ne peuvent pas commencer par un chire. De plus, les minuscules/majuscules sont di erenci ees par la plupart des compilateurs.

1.3.3

Les instructions

Les instructions peuvent etre de deux types : les instructions simples, toujours termin ees par un ; , tel que printf("Hello World !!\n"); les instructions compos ees, qui sont des listes dinstructions simples encadr ees par des accolades, tel que { printf("Hello World !!\n"); printf("Bonjour !!\n"); } Remarque : toutes les instructions simples se terminent par un point-virgule. Son oubli est lerreur la plus courante !

18

CHAPITRE 1. INTRODUCTION

1.3.4

Organisation dun programme C

Un programme C est alors un assemblage de fonctions, elles-m emes listes de blocs dinstructions. Ainsi, un programme C aura toujours laspect pr esent e sur le programme 2. Cest-` a-dire, outre les commentaires et les directives pour le pr eprocesseur qui peuvent etre ins er es ` a tout moment, on commence par d eclarer les variables globales (qui devront etre connues par tous les el ements du programme). Ensuite, on d enit toutes les fonctions, en particulier la fonction main. Chaque fonction est d enie par son en-t ete, puis un corps. Le corps dune fonction commence, comme le programme, par d eclarer toutes les variables n ecessaires ` a la fonction, qui ne seront connues qu` a lint erieur de la fonction (variables locales). On initialise ensuite ces variables, puis on liste les instructions que la fonction doit eectuer. La fonction main, avec len-t ete int main (int argc, char *argv[]) sera plus courante que le version abr eg ee du programme 1. En eet, elle permet de saisir des valeurs sur la ligne de commande au moment de lex ecution du programme : > gcc prog.c -o prog > prog 14 25 Ainsi, les cha nes de caract` eres "prog", "14" et "25" sont plac ees dans le tableau argv, dans les cases de 0 ` a la valeur de argc 1. Tout ceci etant eectu e par le shell, vous disposez donc de ces variables pr e-remplies. Ensuite, il sut de placer le "14" (contenu dans argv[1]) en tant quentier (la conversion seectue avec la commande atoi, pour ASCII to Integer ) dans la variable a. On fait de m eme avec le "25" dans la variable b. Enn, on appelle la fonction ma_fonction sur ces variables. Gr ace ` a ce petit programme, il est tr` es facile de se familiariser avec les notions de base du langage C. Nous allons pouvoir maintenant rentrer un peu plus dans les d etails, en voyant notamment les di erents types que le langage C sait manipuler, puis ensuite les commandes simples et structur ees qui sont ` a votre disposition pour elaborer un programme capable de faire des calculs laborieux ` a notre place.

ERALIT SUR LA SYNTAXE DU LANGAGE C ES 1.3. QUELQUES GEN

19

generique.c /* Commentaires ` a tout endroit */ /* Directives pour le pr eprocesseur en-t^ ete de fichier, mais egalement ` a tout endroit */ #include <stdlib.h> #include <stdio.h> /* D eclaration des variables globales int ma_variable; */

/* Des fonctions avec en-t^ ete et corps */ /* en-t^ ete de la fonction */ int ma_fonction(int x, int y) /* corps de la fonction */ { /* D eclaration des variables locales ` a la fonction */ int z; /* Liste dinstructions */ z = x + y; /* Renvoi de la valeur de retour de la fonction */ return z; } float ma_deuxieme_fonction() { float x=0; /* ... */ return x; } /* La fonction obligatoire: main */ int main (int argc, char *argv[]) { /* D eclaration des variables locales ` a la fonction */ int a,b,c; /* Initialisation des variables */ a = atoi(argv[1]); b = atoi(argv[2]); c = ma_fonction(a,b); printf("%d + %d = %d \n",a,b,c); return 0; }

Programme 2: Programme g en erique (generique.c)

20

CHAPITRE 1. INTRODUCTION

Chapitre 2 Les types


Sommaire
Les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Les types de base . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Les types entiers (int, short int, long int et long long int) 2.2.2 Les types ottants (float, double et long double) . . . . . . 2.2.3 Le type caract` ere (char) . . . . . . . . . . . . . . . . . . . . . . 2.3 Les types structur es . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.2 Les tableaux ` a plusieurs dimensions . . . . . . . . . . . . . . . 2.3.3 Les structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Les pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Nouveaux types . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1 2.2 21 22 22 22 23 23 23 24 24 24 25

Nous avons d ej` a aper cu le type int dans le programme 1, et entre-aper cu le type float et les tableaux dans le programme 2, mais le langage C conna t de nombreux autres types tr` es utiles. Les plus simples etant les entiers, les r eels et les caract` eres. Le langage C permet egalement de manipuler des types structur es, tels que les tableaux (ensembles dobjets de m eme type) ou les structures (ensembles dobjets de types divers).

2.1

Les types

Un ordinateur stocke toutes les donn ees sous le m eme format, une s erie de bits, dans des octets (blocs de 8 bits) localis es par une adresse m emoire. Ainsi, un entier, une lettre ou un r eel doivent-ils subir un codage sp ecique avant d etre stock es. De plus, conna tre les bits contenus dans un octet ` a une adresse donn ee ne sut pas a conna ` tre la valeur r eellement stock ee. En eet, cette valeur d ependra du type de lobjet que lon a stock e : par exemple, le caract` ere A et lentier 65 sont tous deux cod es de la m eme mani` ere, le type de lobjet permet de d eterminer le codage et donc le contenu r eel. Le langage C sait coder un certain nombre de types usuels, nous allons les etudier dans ce chapitre.

22

CHAPITRE 2. LES TYPES

2.2

Les types de base

Commen cons donc par les types les plus simples et les plus utiles, ` a savoir les entiers, les ottants et les caract` eres.

2.2.1

Les types entiers (int, short int, long int et long long int)

Les entiers sont cod es ` a laide de la repr esentation des nombres entiers relatifs : un bit est r eserv e pour coder le signe, les autres bits codent la valeur absolue du nombre. Le langage C peut g erer plusieurs tailles di erentes dentiers : short int ou simplement short long int ou simplement long long long int ou simplement long long int (lentier par d efaut) Cependant, ces tailles ne sont pas standardis ees, seuls des seuils minimums sont impos es. Cest-` a-dire que ces tailles d ependent de la machine, du syst` eme dexploitation et du compilateur. Avec gcc sous Linux sur un PC, le type short code des entiers sur 16 bits, tandis que les types int et long codent des entiers sur 32 bits et enn le type long long code des entiers sur 64 bits. Ces tailles peuvent etre trouv ees dans le chier limits.h, ou obtenues par linterm ediaire de linstruction C sizeof(<type>). ` titre indicatif, avec 16 bits, on peut repr A esenter des entiers entre -32 768 et 32 767, avec 32 bits, on couvre les valeurs de -2 147 483 648 ` a 2 147 483 647, puis avec 64 bits, les valeurs s etendent de -9 223 372 036 854 775 808 ` a 9 223 372 036 854 775 807. Remarque : ces trois types admettent le qualicatif unsigned. Dans ce cas, il ny a plus de bit pour repr esenter le signe, et seuls les nombres positifs sont cod es. On gagne alors un bit : avec 16 bits, on peut repr esenter des entiers non-sign es entre 0 et 65 535, avec 32 bits, on couvre les valeurs de 0 ` a 4 294 967 295, puis sur 64 bits, les valeurs s etendent de 0 ` a 18 446 744 073 709 551 615. Cependant, lemploi de ce qualicatif doit etre limit e` a des situations particuli` eres. Type short int/long long long unsigned short unsigned int/long unsigned long long Espace [-32 768, 32 767] [-2 147 483 648, 2 147 483 647] [-9 223 372 036 854 775 808, 9 223 372 036 854 775 807] [0, 65 535] [0, 4 294 967 295] [0, 18 446 744 073 709 551 615]

Fig. 2.1 Types entiers sous GCC/Linux

2.2.2

Les types ottants (float, double et long double)

Les types ottants codent les nombres r eels de mani` ere approch ee avec la notation scientique , une mantisse et lexposant en base 2 (ex. 234 245 ).

2.3. LES TYPES STRUCTURES

23

Le C propose trois tailles pour repr esenter ces ottants, avec une mantisse et un exposant de tailles variables : float double, le ottant en double pr ecision long double, un type r ecent qui propose une pr ecision quadruple. Comme pour les entiers, les tailles et pr ecisions des ottants ne sont pas standardis ees, mais peuvent etre trouv ees dans le chier float.h. Avec gcc sous Linux sur un PC, nous avons : pour les float, une mantisse sur 24 bits et un exposant sur 8 bits, proposant une pr ecision de lordre de 107 ; pour les double, une mantisse sur 53 bits et un exposant sur 11 bits, proposant une pr ecision de lordre de 2 1016 ; pour les long double, une mantisse sur 64 bits et un exposant sur 16 bits, proposant une pr ecision de lordre de 1019 . Type float double long double Mantisse 24 53 64 Pr ecision 107 2 1016 1019 Min 1038 2 10308 104931 Max 3 1038 10308 104932

Fig. 2.2 Types ottants sous GCC/Linux

2.2.3

Le type caract` ere (char)

Les caract` eres sont essentiels, notamment pour ecrire du texte, manipuler des lettres, etc. En C, ils sont repr esent es comme des entiers, sur un octet (entre 0 et 255) en utilisant la table de conversion ASCII. Cependant, cette table de conversion est transparente pour lutilisateur, en notant le caract` ere entre apostrophes . Ainsi, la notation A d esignera le caract` ere A .

2.3

Les types structur es

Un type semble manquer dans la liste ci-dessus, il sagit des cha nes de caract` eres, cest-` a-dire les mots ou les phrases. En fait, elles sont repr esent ees comme des tableaux de caract` eres. De nombreuses commandes standard permettent de manipuler ces tableaux particuliers de caract` eres (voir la section 11.1).

2.3.1

Les tableaux

Les tableaux permettent de stocker une grande quantit e dobjets de m eme type. Ainsi, les instructions du programme 3 d eclarent des tableaux de 10 entiers, de 10 ottants ou de 10 caract` eres (cha ne de caract` eres). Les cases se d enommeront alors tab_i[0] jusqu` a tab_i[9] (pour le tableau dentiers).

24

CHAPITRE 2. LES TYPES

tableaux.c int tab_i[10]; float tab_f[10]; char tab_c[10];

Programme 3: Tableaux (tableaux.c)

2.3.2

Les tableaux ` a plusieurs dimensions

Il est possible de d enir des tableaux ` a plusieurs dimensions. Il sagit en fait dun tableau de tableaux : int tab[10][5];

est un tableau de 10 tableaux de 5 entiers chacuns. Ainsi, tab[0] d esigne le premier tableau, et tab[0][0] la premi` ere case de ce premier tableau.

2.3.3

Les structures

Les structures, quant ` a elles, permettent de stocker plusieurs objets de types divers. On d enit une structure comme pr esent e dans le programme 4. structure.c struct ma_structure { int nombre; float valeur; };

Programme 4: Structure (structure.c) Le type struct ma_structure regroupe alors deux champs, un entier et un ottant. Un objet st de type struct ma_structure contient ces deux valeurs dans ses deux champs d enomm es st.nombre et st.valeur. Lexemple dune structure pour manipuler des complexes est donn e dans la section 7.3.

2.4

Les pointeurs

Ce type un peu particulier pourrait egalement etre class e dans les types de base, mais les pointeurs ne semblent sans doute pas naturels, ni essentiels, au premier coup dil, et

2.5. NOUVEAUX TYPES

25

pourtant nous y consacrerons tout un chapitre (voir chapitre 8). En eet, comme nous lavons vu pr ec edemment, tout objet est stock e en m emoire. Son contenu est donc caract eris e par ladresse m emoire de ce stockage et du type de lobjet. Un pointeur contient cette adresse. Sa taille est donc la taille n ecessaire pour coder une adresse m emoire (en g en eral 32 bits). Un pointeur est de plus, en g en eral, associ e` a un type dobjet, pour pouvoir manipuler lobjet correctement (ce que lon verra plus loin). Ainsi, un pointeur sur un objet obj de type int contient ladresse o` u est stock e lobjet obj. Son type est not e int * .

2.5

Nouveaux types

Les tableaux ou les structures permettent de faire des tableaux de tableaux de structures de tableaux, etc. On obtient alors des types avec des noms ` a dormir dehors ! ! La commande typedef permet de d enir des synonymes pour des noms de types. Ainsi, par exemple, la structure d enie ci-dessus est de type struct ma_structure. Si on veut d enir un tableau de taille 20 dune telle structure, son type sera alors struct ma_structure[20], etc. On peut alors simplier ce nom nal, sil doit etre beaucoup utilis e. Par exemple, dans le programme 5, on renomme le nouveau type de tableau de 20 structures en tabs. Puis, un tel tableau d enomm e T est ais ement d eclar e. On peut aussi souhaiter aussit ot renommer le nouveau type r esultant de linstruction struct new_structure. Le programme 5 d enit ce nouveau type sous le nom point2D. On peut m eme se passer du nom temporaire, comme le montre la d enition du type point3D du m eme programme.

26

CHAPITRE 2. LES TYPES

typedef.c typedef struct new_structure { float abscisse; float ordonnee; } point2D; typedef struct { float abscisse; float ordonnee; float hauteur; } point3D; struct ma_structure { int nombre; float valeur; }; typedef struct ma_structure[20] tabs; point2D p2; point3D p3; tabs T;

Programme 5: Typedef (typedef.c)

Chapitre 3 Les variables et les constantes


Sommaire
3.1 D eclaration des variables . . . . . . . . . . . . 3.1.1 D eclaration des types simples . . . . . . . . . 3.1.2 D eclaration des tableaux et pointeurs . . . . 3.1.3 D eclaration des objets complexes . . . . . . . 3.2 Initialisation des variables . . . . . . . . . . . 3.3 Constantes . . . . . . . . . . . . . . . . . . . . 3.3.1 Types simples . . . . . . . . . . . . . . . . . . 3.3.1.1 Constantes de type entier . . . . . . 3.3.1.2 Constantes de type ottant . . . . . 3.3.1.3 Constantes de type caract` ere . . . . 3.3.2 Types complexes . . . . . . . . . . . . . . . . 3.4 Dur ee de vie et visibilit e des variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 28 28 29 30 30 30 30 30 31 31 31

Un programme informatique sert ` a travailler sur des valeurs, tel que faire des calculs sur des entiers ou des ottants. Ces valeurs doivent alors etre stock ees en m emoire. On utilise alors des variables si elles doivent varier. En revanche, ces variables sont en g en eral initialis ees par des valeurs constantes. Les variables doivent etre d eclar ees, pour sp ecier le type de la variable en question. Cette d eclaration attribut de plus un emplacement m emoire ` a la variable, qui lui est r eserv e pendant toute sa dur ee de vie, d esign e par le pointeur de la variable. Il faut ensuite initialiser la variable. En eet, lors de la d eclaration, un emplacement m emoire est attribu e` a la variable, sans toucher au contenu, qui peut donc valoir nimporte quoi. Pour cela, nous aurons alors ` a faire aux constantes, dont la syntaxe est sp ecique au type.

3.1

D eclaration des variables

La d eclaration dune variable consiste donc, dans un premier temps, ` a pr eciser au compilateur le type de la variable que lon va utiliser, et donc le mode de codage quil va devoir eectuer pour le stockage. Ensuite, en fonction du type de la variable, il va r eserver une place m emoire plus ou moins importante (selon quil sagit dun short ou dun long).

28

CHAPITRE 3. LES VARIABLES ET LES CONSTANTES

3.1.1

D eclaration des types simples

Ces d eclarations seectuent simplement en donnant le type de la variable suivi du nom de la variable en question : int i; float x; double y; char c; Nous avons alors d eclar e une variable enti` ere de type int d enomm ee i, ainsi que deux variables ottantes, une de type float d enomm ee x et une de type double d enomm ee y, et enn une variable de type char d enomm ee c. Lorsque lon souhaite d eclarer plusieurs variables du m eme type, on peut regrouper la d eclaration sur une seule ligne : int i,j,k; float x,y;

3.1.2

D eclaration des tableaux et pointeurs

Formellement, les tableaux et les pointeurs ne sont pas identiques, mais nous ninsisterons pas sur les di erences. Pour un tableau ou un pointeur, la d eclaration est alors aussi simple, sachant que la taille du tableau doit etre une constante, et non une variable : float *pfloat; int tab[10]; char st[]; Ainsi, nous venons de d eclarer un pointeur pfloat sur un float, ainsi quun tableau tab de 10 entiers. Ces deux d eclarations ont du m eme coup r eserv e lespace m emoire n ecessaire pour stocker le pointeur pfloat ainsi que le tableau tab et ses dix cases. En revanche, la d eclaration du tableau de caract` eres st na pas r eserv e de m emoire pour ses cases, puisque la longueur est inconnue. Seule la zone m emoire pour stocker ladresse du futur tableau est r eserv ee, ainsi st nest rien dautre quun pointeur, qui ne pointe sur rien. Lorsque la zone m emoire aura et e r eserv ee (gr ace ` a la commande malloc que nous etudierons dans le chapitre 8 d edi e aux pointeurs), nous pourrons alors d enir cette valeur. Cette m ethode est la seule pour manipuler des tableaux dont la taille nest pas une constante connue au moment de la compilation. En revanche, tab est un pointeur de type int qui pointe sur le d ebut de lespace m emoire r eserv e pour les 10 cases du tableau (voir la gure 3.1). La premi` ere case du tableau est donc ` a cette adresse, la deuxi` eme case, ` a cette adresse incr ement ee de la taille dun entier (ce que lon conna t, puisque le pointeur est typ e en tant que pointeur sur un int), etc.

DES VARIABLES 3.1. DECLARATION

29

?
int t[]; t = int *t;

t[0] int t[4]; t t[1] t[2] t[3]

Fig. 3.1 D eclaration des tableaux

3.1.3

D eclaration des objets complexes

Finalement, pour tout type, tel que le type tableau de structures tabs d eni ` a la n du chapitre pr ec edent, on d eclare une variable comme la variable T du programme 5. La taille dun tel objet etant bien d enie, un tableau de 20 cases contenant chacune un entier et un ottant, la m emoire est egalement r eserv ee. Ainsi T est un pointeur vers une zone m emoire qui contient 20 cases cons ecutives dobjets de type struct ma_structure. En revanche, consid erons le type et la d eclaration suivante :

typedef struct { int length; int value[]; } bigInteger; bigInteger bI;

La variable bI est bien d eclar ee comme etant de type bigInteger. Elle contient donc un champ de type entier, bI.length, et un champ de type tableau dentiers, sans longueur. Pour ce dernier, il sagit donc dun pointeur sans destination pr ecise (voir la gure 3.2). Il faudra donc linitialiser ult erieurement, lorsquun espace m emoire aura et e r eserv e (gr ace a la commande malloc que nous verrons plus loin dans le chapitre 8 d ` edi e aux pointeurs).
bigInteger bI; bI.length bI.value
entier pointeur

?
Fig. 3.2 D eclaration des structures

30

CHAPITRE 3. LES VARIABLES ET LES CONSTANTES

3.2

Initialisation des variables

La d eclaration des variables se contente de signaler le type de la variable et de r eserver, le cas ech eant, de la m emoire. Dans ce dernier cas, la r eservation de m emoire ne modie pas son contenu pr ec edent. Ainsi, la variable prend la valeur associ ee au contenu de la m emoire : ca peut etre nimporte quoi. Il faut donc toujours initialiser une variable avant de lutiliser. Ainsi,

int i; i = 0;

d eclare une variable enti` ere i, puis linitialise ` a 0. La d eclaration et linitialisation peuvent etre faites en une seule etape au lieu de deux :

int i = 0;

En fait, linitialisation consiste ` a aecter une valeur constante ` a la variable. La syntaxe des constantes est d ecrite dans la section suivante.

3.3
3.3.1

Constantes
Types simples

Les constantes pour les types simples ont une syntaxe particuli` ere, etant donn e quil existe plusieurs types dentiers et de ottants, puis quil existe egalement plusieurs notations. 3.3.1.1 Constantes de type entier

Les entiers sont construits ` a partir des chires (et des lettres pour une notation en hexad ecimale). On ajoute alors eventuellement un suxe l ou L pour d esigner une constante de type long et/ou le suxe u ou U pour d esigner le qualicatif unsigned. Aucun pr exe signale que le nombre est exprim e en base 10, tandis que les pr exes 0 et 0x pr ecisent respectivement une notation en octale ou en hexad ecimale. Ainsi, 0377 d esigne lentier 255, 0xF d esigne lentier 15. En revanche, 120L d esigne lentier 120 de type long. 3.3.1.2 Constantes de type ottant

Les ottants peuvent bien s ur etre d esign es par des nombres ` a virgule (enn, avec un point . !). On ajoute eventuellement un suxe f ou F pour d esigner une constante de type float ou le suxe l ou L pour d esigner le type long double. On peut egalement utiliser la notation scientique 123E+3 ou -142E-4.

DE VIE ET VISIBILITE DES VARIABLES 3.4. DUREE

31

3.3.1.3

Constantes de type caract` ere

Les caract` eres sont simplement d esign es entre apostrophes. Ainsi, la constante a d esigne le caract` ere a minuscule. On peut egalement noter ces lettres par leur code ASCII en utilisant les notations octales ou hexad ecimales, pr ec ed ees dun backslash. Ceci permet de noter les caract` eres non achables. Certains caract` eres admettent des abbr eviations : \101 et \x41 d esignent le caract` ere A, de code ASCII 65, ( egalement A) \0 et \x0 d esignent le caract` ere nul (d elimite la n des cha nes de caract` eres) \12 et \xA d esignent le saut de ligne ( egalement \n) \13 et \xB d esignent le retour chariot ( egalement \r)

3.3.2

Types complexes

Pour les types complexes (tableaux et structures), on initialise chaque case ou champ ind ependamment, un par un. On peut egalement en initialiser plusieurs ` a la fois : int inttab[5] tableau de 5 entiers contenant les = { 2, 5, -2, 0, 10 }; valeurs 2, 5, -2, 0 et 10 float floattab[4] tableau de 4 ottants contenant les = { 2.0, 5e-3, -2e10, 10.04 }; valeurs 2.0, 5 103 , 2 1010 et 10.04 char mot[5] = "essai"; tableau de 5 caract` eres e, s, s, a, i int tab[10] tableau de 10 entiers dont les 4 premi` eres = { 2, 5, -2, 10 }; cases sont initialis ees ` a 2, 5, -2 et 10 char *mot = "essai"; pointeur sur un caract` ere, initialis e` a ladresse de la cha ne "essai" char chaine[10] = "mot"; tableau de 10 caract` eres, les premi` eres cases sont initialis ees ` a m, o, t et \0 struct carte { d enition du type struct carte char[] nom; d eclaration dune variable prem int age; initialisation avec prem.nom="durand" } prem = { "durand", 10 }; et prem.age=10

3.4

Dur ee de vie et visibilit e des variables

Les variables ont une dur ee de vie plus ou moins longue, ainsi quune visibilit e variable. Voir les programmes 6 et 7 pour un exemple dapplication. Les chiers variables.c et options.c sont deux modules de compilation di erents, le chier variables.c etant lunit e principale, puisquelle contient la fonction main. On les compile dun seul coup de la fa con suivante : >gcc options.c variables.c -o variables >variables 4 10 + 4 = 14

32

CHAPITRE 3. LES VARIABLES ET LES CONSTANTES

globale les variables d enies en dehors de toute fonction sont dites globales. Elles sont vues/accessibles par toutes les fonctions (au moins du module). Elles ont une dur ee de vie egale au temps dex ecution du programme. Telles les variables b et c d enies en t ete du chier variables.c. locale les variables d enies dans une fonction ou dans un bloc sont a priori visibles et existantes dans le seul bloc en question. Telles les variables b et d d eclar ees en t ete de la fonction main. Elles nexisteront que dans cette fonction. Si une telle variable a un nom identique ` a une variable globale, la variable globale ne sera pas visible ni accessible dans cette zone, mais seule la variable locale. Telle la variable locale b d enie en t ete de la fonction main qui masque la variable globale du m eme nom. extern il sagit dun qualicatif qui permet dutiliser dans une unit e de compilation une variable ou un type d enis dans un autre module. Ainsi, la variable a d enie dans lunit e options.c est annonc ee comme utile dans lunit e principale variables.c. static il sagit dun qualicatif qui modie la visibilit e de la variable. Une variable globale static ne pourra pas etre utilis ee par une autre unit e de compilation (voir le qualicatif extern). Une variable locale stactic aura une dur ee de vie egale a lex ` ecution du programme mais ne sera visible que dans le bloc (ou la fonction) dans lequel elle a et e d enie. register ce qualicatif informe le compilateur que la variable sera tr` es utilis ee, et lui demande de la mettre, si possible, dans un registre du processeur. Ces deux derniers qualicatifs sont dun usage limit e. Notamment lutilisation des registres. En eet, le nombre de registres est tr` es faible, et il vaut mieux faire conance au compilateur, et notamment ` a loptimiseur de code, pour les optimisations de ce genre.

DE VIE ET VISIBILITE DES VARIABLES 3.4. DUREE

33

variables.c #include <stdlib.h> #include <stdio.h> extern int a; int b = 0; int c; int main (int argc, char *argv[]) { int b; int d; b = atoi(argv[1]); c = a+b; d = a*b; printf("%d + %d = %d \n",a,b,c); printf("%d * %d = %d \n",a,b,d); return 0; }

Programme 6: Variables (variables.c)

options.c int a=10;

Programme 7: Variables annexe (options.c)

34

CHAPITRE 3. LES VARIABLES ET LES CONSTANTES

Chapitre 4 Les entr ees-sorties


Sommaire
4.1 Lachage avec printf . 4.1.1 Simple achage . . . 4.1.2 Formattage des sorties 4.2 La saisie avec scanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 35 36 37

On a vu comment passer des arguments par linterm ediaire de la ligne de commande. Ils se trouvent stock es dans le tableau argv[] de longueur argc, les arguments de la fonction main : int main(int argc, char *argv[]). Il est egalement possible que le programme pose des questions ` a lutilisateur et lise les donn ees entr ees au clavier. Ceci est eectu e avec la fonction scanf. Nous d ecrirons donc son usage. Cependant, elle est moins utile que la fonction printf qui permet d ecrire des donn ees ` a l ecran. Le programme 8 pr esente un exemple dutilisation des fonctions printf et scanf, dont lex ecution donne l ecran suivant : >gcc io.c -o io >io Entrer deux entiers : 12 76 Entrer deux flottants : 3.54 9.234 12 * 76 = 912 3.54 + 9.23 = 12.77

4.1
4.1.1

Lachage avec printf


Simple achage

La fonction printf sert ` a acher des donn ees ` a l ecran. Les cha nes de caract` eres constantes sachent telles que, mais les autres constantes et les variables doivent etre int egr ees de fa con particuli` ere, sp ecique au type et au format dachage.

36

CHAPITRE 4. LES ENTREES-SORTIES

io.c #include <stdio.h> int main () { int a,b,c; float x,y,z; printf("Entrer deux entiers : "); scanf("%d %d",&a,&b); printf("Entrer deux flottants : "); scanf("%f %f",&x,&y); c = a*b; z = x+y; printf("%5d * %5d = %5d \n",a,b,c); printf("%5.2f + %5.2f = %5.2f \n",x,y,z); return 0; }

Programme 8: Entr ees/Sorties (io.c) Ainsi, printf("Affichage"); ecrit le mot Achage ` a l ecran. Pour acher le contenu dune variable enti` ere, on sp ecie %d (voir le programme 2) pour pr eciser quil sagit dun type entier, puis on pr ecise le nom de la variable ` a ins erer en n : printf("La variable i vaut %d",i); Si on veut acher la variable en octal ou en hexad ecimal, on utilise %o et %x respectivement. Pour les ottants, on utilise %f ou %e selon que lon souhaite un achage standard ou en notation exponentielle. Une liste plus compl` ete peut etre trouv ee gure 4.1 pour acher les entiers, les ottants et les cha nes de caract` eres. La fonction printf retourne un entier qui peut etre r ecup er e ou non. Cet entier vaut le nombre de caract` eres ach es (sans le caract` ere de n de cha ne de caract` eres).

4.1.2

Formattage des sorties

Un formattage plus complexe est possible avec cette commande, notamment pour pr eciser le nombre despaces que lon pr evoit pour lachage dun entier, pour former des colonnes : printf("%4d et %5d",i,j); ache les variables enti` eres i et j en ins erant, devant, des espaces de fa con ` a ce que les espaces plus lachage du i (resp. du j) prennent 4 caract` eres (resp. 5 caract` eres).

4.2. LA SAISIE AVEC SCANF

37

Type et Variable short i; int j; short i; int j; short i; int j; float x; double float x; double float x; double long double z; long double z; long double z; char c; char m[10];

Achage long k; printf("%hd %d %ld",i,j,k); long k; printf("%ho %o %lo",i,j,k); long k; printf("%hx %x %lx",i,j,k); y; printf("%f %lf",x,y); y; printf("%e %le",x,y); y; printf("%g %lg",x,y); printf("%Lf",z); printf("%Le",z); printf("%Lg",z); printf("%c",c); printf("%s",m);

Format d ecimal octal hexad ecimal d ecimal (avec point) exponentiel le plus court des deux d ecimal (avec point) exponentiel le plus court des deux caract` ere cha ne de caract` eres

Fig. 4.1 Achage des variables avec printf

3 et 12 et 2353 et

9 235 4532

Pour les ottants, il est de m eme possible de pr eciser le nombre de chires apr` es la virgule, ainsi que le nombre total de caract` eres (point compris) : printf("%6.2f %.3Lf",x,y); ache la variable ottante x avec 2 chires apr` es la virgule, mais en ins erant des espaces devant an que le tout fasse 6 caract` eres. Tandis que le variable de type long double y sera simplement ach ee avec 3 chires apr` es la virgule, sans sp ecication de la longueur totale. Enn, il est egalement possible de formatter lachage des cha nes de caract` eres en pr ecisant la taille globale (le nombre despaces ` a ins erer en t ete) : printf("%20s",chaine); ache la cha ne de caract` ere chaine avec des espaces devant an que le tout fasse 20 caract` eres.

4.2

La saisie avec scanf

La fonction scanf permet de saisir des valeurs tap ees au clavier pendant lex ecution du programme. La syntaxe est tr` es semblable ` a celle de la fonction printf, mais en sens inverse : scanf("valeurs %d et %d",&i,&j); attend, au clavier, une phrase de la forme valeurs 10 et 31 et mettra la valeur 10 dans la variable i et la valeur 31 dans la variable j. On remarquera que la notation des variables di` ere de leur utilisation avec printf. En eet, il faut indiquer ` a la fonction scanf ladresse de la variable dans laquelle on veut stocker la valeur scann ee, do` u le & qui acc` ede au pointeur associ e` a la variable qui suit (voir le chapitre 8 sur les pointeurs).

38

CHAPITRE 4. LES ENTREES-SORTIES

Type et Variable short i; int j; long k; short i; int j; long k; short i; int j; long k; float x; double y; long double z; float x; double y; long double z; char c; char m[10];

Achage scanf("%hd",&i); scanf("%d",&j); scanf("%ld",&k); scanf("%ho",&i); scanf("%o",&j); scanf("%lo",&k); scanf("%hx",&i); scanf("%x",&j); scanf("%lx",&k); scanf("%f",&x); scanf("%lf",&y); scanf("%Lf",&z); scanf("%e",&x); scanf("%le",&y); scanf("%Le",&z); scanf("%c",&c); scanf("%s",m); scanf("%s",&m[0]);

Format d ecimal

octal

hexad ecimal

d ecimal (avec point)

exponentiel caract` ere cha ne de caract` eres

Fig. 4.2 Saisie avec scanf

La fonction scanf retourne un entier, qui peut etre r ecup er e ou non : k = scanf("valeurs %d et %d",&i,&j); la valeur retourn ee, stock ee dans k, vaut le nombre de variables scann ees. En eet, si lutilisateur tape valeurs 10 est 31, le 10 sera lu, mais ne voyant pas le mot et appara tre, rien dautre nest lu. Ainsi la fonction scanf retourne 1. Si lutilisateur tape nimporte quoi, la fonction scanf retourne 0. Pour une utilisation normale, telle que la phrase entr ee ci-dessus, la fonction scanf retournera 2.

Chapitre 5 Les op erateurs et les expressions

Sommaire
5.1 Les op erateurs . . . . . . . . . . . . . . . . . . . . 5.1.1 Les op erateurs arithm etiques . . . . . . . . . . . 5.1.1.1 Op erateurs standard . . . . . . . . . . . 5.1.1.2 Op erateurs dincr ementation ++ et 5.1.1.3 Op erateurs de signe . . . . . . . . . . . 5.1.1.4 Op erateurs de d ecalage . . . . . . . . . 5.1.2 Op erateur de conversion de type ( cast ) . . . . 5.1.3 Op erateur de taille . . . . . . . . . . . . . . . . . 5.1.4 Op erateurs logiques . . . . . . . . . . . . . . . . 5.1.5 Op erateurs de masquage . . . . . . . . . . . . . . 5.1.6 Op erateurs de relations . . . . . . . . . . . . . . 5.1.7 Op erateur daectation . . . . . . . . . . . . . . 5.1.8 Op erateurs abr eg es . . . . . . . . . . . . . . . . . 5.2 Les expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 40 40 40 42 42 42 42 43 43 43 43 44 44

Maintenant que lon conna t les variables, les constantes, comment les d enir et les acher, voyons comment les manipuler, les modier avec les op erations standard.

5.1

Les op erateurs

Les op erateurs sont des commandes qui sappliquent ` a des op erandes, qui sont des constantes, des variables ou des expressions (voir la section suivante). Les op erateurs peuvent etre r epertori es en fonction du nombre dop erandes quils prennent comme arguments : les op erateurs unaires, qui ne prennent quun argument (voir gure 5.1), les op erateurs binaires, qui prennent deux arguments, tels que les op erateurs arithm etiques classiques (addition, soustraction, etc). Une liste plus compl` ete est propos ee gure 5.2. Enn, lop erateur ternaire, qui prend trois arguments. Commen cons par ce dernier type, qui ne contient quun cas dans le langage C : test ? expr1 : expr2

40

ET LES EXPRESSIONS CHAPITRE 5. LES OPERATEURS

Le premier argument est un test test, en fonction de son etat de validit e, le r esultat de lexpression expr1 ou de lexpression expr2 est retourn e : expr1 pour un test vrai, expr2 pour un test faux. Ceci est une version abr eg ee des instructions de condition (if et else) ` que nous verrons dans le chapitre suivant. A eviter pour produire un programme lisible ! Au lieu d etudier les autres op erateurs plus classiques par leur nombre dop erandes, regroupons-les par cat egories de proc edures.

5.1.1
5.1.1.1

Les op erateurs arithm etiques


Op erateurs standard

Les op erations arithm etiques se font avec les op erateurs classiques : +, -, * et /. Si les arguments sont des entiers, les op erations retournent des entiers. Notamment, la division / retourne le quotient de la division euclidienne, tandis que % retourne le reste de cette division euclidienne. Sinon, les quatre op erateurs de base manipulent des ottants. arithmetique.c int main () { int a,b,c; float x,y,z; a c c c c c c = = = = = = = 5; b = 7; b/a; b%a; b++; ++a; a >> 3; b << 2;

/* /* /* /* /* /*

alors alors alors alors alors alors

c c b a c c

= = = = = =

1 */ 2 */ 8 et c = 7 */ 6 et c = 6 */ 48 */ 2 */

x = 3.01; y = 0.02; z = -x*y; /* alors z = -0.0602 */ return 0; }

Programme 9: Op erateurs arithm etiques (arithmetique.c)

5.1.1.2

Op erateurs dincr ementation ++ et

Il existe des op erateurs dincr ementation et de d ecr ementation abbr eg es : i++; et ++i; reviennent ` a ecrire i = i+1; i--; et --i; reviennent ` a ecrire i = i-1;

5.1. LES OPERATEURS

41

Cat egorie Op erateur arithm etique ++ + type (type) adressage & (pointeurs) * logique masquage divers ! ~ sizeof

Action d ecr ementation incr ementation inverser le signe conrmer le signe convertit le type de la variable ( cast ) retourne ladresse (pointeur) dun objet retourne le contenu dune variable a ladresse indiqu ` ee NOT logique NOT bit ` a bit taille de lobjet (ou du type) en octets

Fig. 5.1 Op erateurs unaires

Cat egorie Op erateur arithm etique + / % d ecalages < < > > logique && || masquage & | ^ relations < <= > >= == != divers =

Action addition soustraction multiplication division (enti` ere si entre entiers) reste de la division euclidienne vers la gauche vers la droite ET logique OU logique ET bit ` a bit OU bit ` a bit XOR bit ` a bit inf erieur strict inf erieur ou egal sup erieur strict sup erieur ou egal egal di erent aectation

Fig. 5.2 Op erateurs binaires

42

ET LES EXPRESSIONS CHAPITRE 5. LES OPERATEURS

Cependant, les valeurs retourn ees par ces op erations di` erent : j = i++; est une post-incr ementation de i. Cest-` a-dire que j prend la valeur de i, puis i est incr ement e; j = ++i; est une pr e-incr ementation de i. Cest-` a-dire que i est incr ement e, puis j prend la valeur du i, apr` es incr ementation. Il en est de m eme pour les i--; et --i; (voir le programme 9). 5.1.1.3 Op erateurs de signe

Les op erateurs unaires + et permettent de conrmer on dinverser le signe : j = +i ; k = -i ; 5.1.1.4 Op erateurs de d ecalage

Les op erateurs de d ecalage peuvent etre assimil es ` a des op erateurs arithm etiques, bien que leur usage standard soit pour des masquages. Mais, en fait, un d ecalage de n ` a n droite revient ` a une division par 2 , tandis quun d ecalage ` a gauche de n revient ` a une n multiplication par 2 .

5.1.2

Op erateur de conversion de type ( cast )

Si des scalaires de di erents types interviennent dans une expression arithm etique, le type nal de lexpression est le type le plus g en eral des divers el ements : les types plus stricts sont automatiquement cast es dans le type plus g en eral (voir la gure 5.3). On short int long float double long double Fig. 5.3 Cast automatique peut egalement forcer la conversion de type, en mettant le nouveau type entre parenth` eses devant la variable : int a = 5; int b = 7; float c,d; c = a/b; d = (float) a/b; Dans le programme ci-dessus, la variable c prend le r esultat de la division euclidienne (entre entiers), donc 0. Tandis que la variable d prend la r esultat de la division entre lentier a converti en float et lentier b. Ainsi, le r esultat est un float : 0.714286.

5.1.3

Op erateur de taille

Puisque nous somme dans les types, nous avons vu quil pouvait etre utile de conna tre la taille dun objet, pour savoir la place n ecessaire en m emoire. Nous verrons encore plus

5.1. LES OPERATEURS

43

lutilit e pour lallocation dynamique de m emoire, dans le chapitre sur les pointeurs (voir chapitre 8). La commande sizeof fournit cette information, en nombre doctets : sizeof(int) retourne la taille dun entier, cest-` a-dire 4 octets pour gcc sous linux. De m eme, si a est une variable de type int, sizeof(a) retourne la taille de cette variable, et donc la taille dun int, soit 4 octets.

5.1.4

Op erateurs logiques

Il est possible de manipuler des valeurs bool eennes, repr esent ees par des entiers : le 0 valant faux, tandis que toute valeur non nulle repr esente le vrai (en g en eral, on utilise simplement le 1). Ainsi, les op erateurs !, && et || repr esentent respectivement le NOT, ET et OU logiques.

5.1.5

Op erateurs de masquage

Il est egalement possible de manipuler ind ependamment chaque bit dun entier, un ` a un, avec des op erations logiques. Ceci permet notamment de masquer certains bits, mais egalement den inverser, etc. Ainsi, les op erateurs ~, &, | et ^ repr esentent respectivement le NOT, ET, OU et XOR (OU exclusif) eectu es bit ` a bit.

5.1.6

Op erateurs de relations

Pour comparer certaines valeurs, on peut utiliser les relations binaires classiques, d egalit e mais egalement dordre strict ou non : le test d egalit e est eectu e avec lop erateur == tandis que le test de di erence est eectu e avec lop erateur !=. les comparaisons strictes sont eectu ees avec les op erateurs < et >. les comparaisons larges sont eectu ees avec les op erateurs <= et >=. Chacun de ces tests retourne un bool een (cod e sous forme dentier, comme vu pr ec edemment).

5.1.7

Op erateur daectation

Comme on vient de le voir, le test d egalit e seectue avec lop erateur binaire ==. En eet, lop erateur simple = est lop erateur daectation et non de test d egalit e. Il aecte la valeur de droite ` a la variable de gauche :

int a,b; a = 7; b = a + 9; Si on souhaite aecter la m eme valeur ` a plusieurs variable, il est possible de les aecter en cascade : i = j = k =10 ; qui aecte la valeur 10 aux variables i, j et k.

44

ET LES EXPRESSIONS CHAPITRE 5. LES OPERATEURS

Remarque : Ne pas confondre les op erateurs = et ==. Cest une erreur classique, souvent dicile ` a d etecter, car le compilateur ne peut sen rendre compte, et ne le signale donc pas !

5.1.8

Op erateurs abr eg es

De m eme que les op erateurs dincr ementation informent le compilateur que la variable elle-m eme doit etre incr ement ee, il existe des versions abr eg ees de tous les op erateurs arithm etiques et de masquage qui informent le compilateur que lop eration doit seectuer sur la variable elle-m eme (voir la gure 5.4). Cat egorie Op erateur arithm etique a += 5 ; a -= 7 ; a *= 2 ; a /= 3 ; a %= 3 ; d ecalage a <<= 5; a >>= 7; masquage a &= 0x10 ; a |= 077 ; a ^= 0xFF ; Action a = a + 5; a = a - 7; a = a * 2; a = a / 3; a = a % 3; a = a << 5; a = a >> 7; a = a & 0x10 ; a = a | 077 ; a = a ^ 0xFF ;

Fig. 5.4 Op erateurs abr eg es

5.2

Les expressions

Une expression est une suite dop erateurs et dop erandes.

Chapitre 6 Les structures de contr ole


Sommaire
6.1 6.2 Instruction . . . . . . . . Les boucles . . . . . . . . 6.2.1 Les boucles while . . 6.2.2 Les boucles for . . . . 6.2.3 Les boucles do while 6.3 Les conditions . . . . . . 6.3.1 Condition if . . . . . 6.3.2 Condition switch . . 6.4 Sauts Inconditionnels . . 6.4.1 break . . . . . . . . . 6.4.2 continue . . . . . . . 6.4.3 return . . . . . . . . 6.4.4 goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 45 46 46 48 49 49 50 50 50 50 50 51

Un programme C est une suite s equentielle dop erations. Il est bien s ur possible de conditionner lex ecution de certaines op erations au r esultat de calculs pr ealables, ou de r ep eter un nombre ni (ou inni) de fois un groupe dop erations.

6.1

Instruction

Dans la suite, nous utiliserons le terme instruction pour d esigner soit une instruction simple, termin ee par un point-virgule, soit un groupe dinstructions simples, encadr e par des accolades.

6.2

Les boucles

Les boucles permettent de r ep eter des instructions un grand nombre de fois. Il existe trois syntaxes di erentes en fonction des besoins.

46

CHAPITRE 6. LES STRUCTURES DE CONTROLE

6.2.1

Les boucles while

La syntaxe g en erale du while est

while (<test>) <instruction> Cela signie que tant que le test <test> est satisfait, linstruction <instruction> est ex ecut ee. Si le test est faux d` es le d ebut, linstruction nest jamais ex ecut ee. Un exemple classique dutilisation de la boucle while est le calcul du PGCD avec la m ethode dEuclide (voir programme 10). pgcd.c #include <stdlib.h> #include <stdio.h> int main (int argc, char *argv[]) { int a,b,r,x,y; x = a = atoi(argv[1]); y = b = atoi(argv[2]); while (b != 0) { r = a % b; a = b; b = r; } printf("pgcd (%d,%d) = %d\n",x,y,a); return 0; }

Programme 10: PGCD (pgcd.c)

6.2.2

Les boucles for

La syntaxe g en erale du for est

for (<initialisation>; <test>; <incrementation>) <instruction>

6.2. LES BOUCLES

47

qui est equivalente ` a

<initialisation> while (<test>) { <instruction> <incrementation> } Une syntaxe plus classique est de la forme

for (i = 0 ; i < n ; i++) <instruction>

qui consiste ` a eectuer n fois linstruction avec des valeurs croissantes pour i. La boucle for est souvent utilis ee avec les tableaux (voir programme 11). carres.c #include <stdio.h> #define N 10 int main (int argc, char *argv[]) { int i; int t[N]; for (i=0; i<N; i++) t[i] = i*i; for (i=1; i<N; i++) t[i] = t[i-1] + t[i]; for (i=0; i<N; i++) printf("%3d -> %3d \n",i,t[i]); return 0; }

Programme 11: Carr es (carres.c)

48

CHAPITRE 6. LES STRUCTURES DE CONTROLE

6.2.3

Les boucles do while

La syntaxe g en erale du do while est

do <instruction> while (<test>) Cette commande est parfois connue dans dautres langages (tel en PASCAL) en repeat until. Elle est tr` es semblable ` a la boucle while, sauf que linstruction <instruction> est ex ecut ee au moins une fois. Un exemple dutilisation de la boucle do while est pr esent ee ci-dessous (voir programme 12). binaire.c #include <stdlib.h> #include <stdio.h> #define N 32 int main (int argc, char *argv[]) { int x,a,i,j; int t[N]; a = atoi(argv[1]); x = a; i = 0; do { t[i] = a % 2; a = a/2; i++; } while (a != 0); printf("%d = ",x); for (j = i-1; j>=0; j--) printf("%d",t[j]); printf("\n"); return 0; }

Programme 12: Binaire (binaire.c)

6.3. LES CONDITIONS

49

6.3

Les conditions

Les ex ecutions conditionnelles peuvent etre de plusieurs types. Le test simple if ... else ..., ou la table de branchement switch/case.

6.3.1

Condition if

La commande de test simple peut etre une condition

if <test> <instruction> o` u linstruction <instruction> est ex ecut ee seulement si le test <test> est satisfait, ou une alternative if <test> <instruction1> else <instruction2> o` u linstruction <instruction1> est ex ecut ee si le test <test> est satisfait, sinon cest linstruction <instruction2> qui est eectu ee, tel que dans le programme de parit e (voir programme 13). parite.c #include <stdlib.h> #include <stdio.h> int main (int argc, char *argv[]) { int a; a = atoi(argv[1]); if (a%2 == 0) printf("nombre pair \n"); else printf("nombre impair \n"); return 0; }

Programme 13: Parit e (parite.c)

50

CHAPITRE 6. LES STRUCTURES DE CONTROLE

6.3.2

Condition switch

Lorsque les alternatives sont plus nombreuses, on peut utiliser la commande switch qui d esigne la valeur ` a etudier, suivie des instructions ` a ex ecuter en fonction des divers cas (commande case). Plus pr ecis ement, lex ecution des commandes commence lorsque la valeur etudi ee appara t, jusqu` a la n (ou jusquau break). Si la valeur nappara t jamais, le cas default englobe toutes les valeurs : switch (a) { case 1: <instruction1> case 2: <instruction2> break; case 4: <instruction4> break; default: <instruction> } Ainsi, si a vaut 1, le programme est branch e sur linstruction <instruction1>, suivie de linstruction <instruction2>. La commande break interrompt lex ecution pour la poursuivre apr` es laccolade. Si a vaut 2, le programme est branch e sur linstruction <instruction2>. La commande break interrompt lex ecution pour la poursuivre apr` es laccolade. Si a vaut 4, le programme est branch e sur linstruction <instruction4>. La commande break interrompt lex ecution pour la poursuivre apr` es laccolade. Enn, dans tous les autres cas, on ex ecute linstruction <instruction>.

6.4

Sauts Inconditionnels

Il existe en C des sauts pour quitter des boucles ou pour aller nimporte o` u dans une fonction. Nous allons juste les citer par soucis dexactitude, mais ils sont ` a bannir dun programme bien structur e (sauf eventuellement pour g erer des erreurs/exceptions).

6.4.1

break

Nous avons vu cette commande en conjonction avec la commande switch. Cest le seul usage propre . En eet, il permet de sortir dun bloc, en sautant automatiquement a linstruction qui suit laccolade fermante. `

6.4.2

continue

Dans une boucle, la commande continue fait passer ` a lit eration suivante (sans ex ecuter les instructions suivantes dans le bloc).

6.4.3

return

Comme on va le voir dans le chapitre suivant, la commande return termine lex ecution dune fonction. Si la fonction est de type void, on utilise la commande return seule. Si

6.4. SAUTS INCONDITIONNELS

51

valeur.c #include <stdlib.h> #include <stdio.h> int main (int argc, char *argv[]) { int a = atoi(argv[1]); switch (a) { case 0: printf("Positif \n"); case 2: printf("Plus petit que 3 \n"); case 4: printf("Plus petit que 5 \n"); case 6: printf("Pair ! \n"); break; case 1: printf("Positif \n"); case 3: printf("Plus petit que 3 \n"); case 5: printf("Plus petit que 5 \n"); case 7: printf("Impair ! \n"); break; default: printf("Plus grand que 8 ! \n"); } return 0; }

Programme 14: Valeur (valeur.c)

la fonction a un autre type, elle doit retourner une valeur (par exemple a) ` a la fonction appelante, avec un return a.

6.4.4

goto

Comme dans les autres langages, le C permet des sauts inconditionnels nimporte o` u a lint ` erieur dune fonction. Il permet ainsi de sortir de plusieurs niveaux de blocs (ce que les fonctions break et continue ne permettent pas). Le goto est associ e` a une etiquette, une cha ne de caract` eres suivie de : .

52

CHAPITRE 6. LES STRUCTURES DE CONTROLE

{ { { ... if (negatif) goto erreur ; } } } erreur : printf("Log dun nombre n egatif !\n");

Chapitre 7 Programme Structur e


Sommaire
7.1 Les fonctions . . . . . . . . . . . . . . . . . . . 7.1.1 D eclaration dune fonction . . . . . . . . . . . 7.1.2 Corps de la fonction . . . . . . . . . . . . . . 7.1.3 Retour de la r eponse . . . . . . . . . . . . . . 7.1.4 Arguments dune fonction . . . . . . . . . . . 7.1.5 Fonction main . . . . . . . . . . . . . . . . . 7.2 R ecursivit e . . . . . . . . . . . . . . . . . . . . 7.3 Les modules . . . . . . . . . . . . . . . . . . . . 7.3.1 Structure . . . . . . . . . . . . . . . . . . . . 7.3.2 Compilation . . . . . . . . . . . . . . . . . . . 7.4 Le pr eprocesseur . . . . . . . . . . . . . . . . . 7.4.1 Inclusions et d enitions . . . . . . . . . . . . 7.4.2 Compilation conditionnelle . . . . . . . . . . 7.4.3 Le pr eprocesseur gcc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 54 54 54 55 56 56 58 58 59 61 61 62 62

Comme nous lavons vu dans lintroduction, pour am eliorer la lisibilit e, un programme doit etre modulaire. Pour cela, nous allons d ecouper le programmes en divers modules, qui eux-m emes contiennent plusieurs fonctions qui sentre-appellent. Le programme contient une (seule) fonction principale, la fonction main, celle qui est appel ee au lancement du programme. Nous allons dabord etudier de plus pr` es les fonctions, puis nous verrons comment d ecouper un programme en plusieurs modules.

7.1

Les fonctions

Les fonctions permettent d ecrire, une fois pour toutes, une s erie dinstructions qui pourront etre ex ecut ees plusieurs fois, sans avoir ` a tout r e ecrire. Une fonction doit avoir un nom explicite, et une en-t ete compl` ete (ou prototype), an que la seule vue de cette ent ete permette de savoir comment utiliser la fonction. Ensuite, est d ecrit le mode op eratoire de cette fonction.

54

CHAPITRE 7. PROGRAMME STRUCTURE

7.1.1

D eclaration dune fonction

Une fonction est d eclar ee gr ace ` a son en-t ete (interface ou prototype ). Le compilateur se contentera de cette interface pour eectuer la premi` ere phase de la compilation : il lui sut de savoir ce que prend la fonction en entr ee et ce quelle retourne (les types de ces el ements). Le contenu, le mode op eratoire de la fonction lui importe peu. int addition (int x, int y) { <corps> } void affichage (int t[], int n) { <corps> } Ainsi, len-t ete de la fonction addition pr ecise que cette fonction prend deux entiers comme arguments (ils seront appel es x et y dans le corps de la fonction), puis quelle retourne un entier. Len-t ete de la fonction affichage pr ecise que cette fonction prend un tableau dentiers (un tableau de taille quelconque qui sera d enomm e t dans le corps de la fonction), ainsi quun entier (qui sera d enomm e n dans le corps de la fonction et sera suppos e d esigner la taille eective du tableau) comme arguments, puis ne retourne rien. En eet, une telle fonction achera des r esultats ` a l ecran, mais ne retournera rien ` a la fonction appelante.

7.1.2

Corps de la fonction

Dans la partie <corps>, le corps de la fonction, est d ecrit le mode op eratoire. Cesta-dire que lon donne la liste des fonctions ` ` a ex ecuter. Ainsi, voici le contenu du corps de la fonction dachage dun tableau : void affichage (int t[], int n) { int i; for (i=0; i<n; i++) printf("%3d ",t[i]); printf("\n"); }

7.1.3

Retour de la r eponse

La fonction affichage ne retournait aucun r esultat, elle se contentait dacher le contenu du tableau, pass e en argument, ` a l ecran. En revanche, certaines fonctions eectuent des calculs ` a retourner ` a la fonction appelante. Ce r esultat est alors retourn e` a laide de la commande return. int addition (int x, int y) { int z; z = x + y; return z; }

7.1. LES FONCTIONS

55

7.1.4

Arguments dune fonction

Il faut bien voir les arguments des fonctions comme des variables muettes . Par exemple, pour appeler la fonction affichage sur un tableau s de longueur l, on ecrit affichage(s,l). Alors le contenu de la variable l est copi e dans une variable locale ` a la fonction, appel ee n. De m eme, le contenu de la variable s (le pointeur vers la zone m emoire qui contient le tableau) est copi e dans une variable locale ` a la fonction, appel ee t. De m eme, pour obtenir la somme de deux entiers a et b, on appelle addition(a,b). Pour stocker le r esultat retourn e par la fonction dans une variable enti` ere c, d ej` a d eclar ee, on ecrit c = addition(a,b). Alors le contenu de la variable a est copi e dans une variable locale ` a la fonction, appel ee x. De m eme, le contenu de la variable b est copi e dans une variable locale ` a la fonction, appel ee y. Cest lordre des arguments qui permet de savoir le nom quils auront au sein de la fonction. Comme la fonction manipule des copies des variables pass ees comme argument, si la fonction modie les variables locales, les variables initiales demeurent inchang ees. Voir le programme 15. incrementation.c #include <stdlib.h> #include <stdio.h> int incrementation(int x) { x++; return x; } int main (int argc, char *argv[]) { int a,b; a = atoi(argv[1]); b = incrementation(a); printf("a = %d, b = %d\n",a,b); return 0; }

Programme 15: Incr ementation (incrementation.c) Dans ce programme, la variable a (locale ` a la fonction main) prend la valeur pass ee sur la ligne de commande (par exemple 10). Lors de lappel de la fonction incrementation, son contenu est copi e dans une variable x, locale ` a la fonction incr ementation. Cette

56

CHAPITRE 7. PROGRAMME STRUCTURE

variable x a donc, initialement, la m eme valeur que a, cest-` a-dire 10. Elle est incr ement ee, alors x vaut d esormais 11, mais a na pas et e modi ee. La fonction incr ementation retourne la valeur de x ` a la fonction appelante (la fonction main), qui la stocke dans la variable b. Ainsi, dans cette fonction main, la variable a est inchang ee, et vaut 10. La variable b a pris la valeur retourn ee par la fonction incrementation, et vaut donc 11 : >incrementation 10 a = 10, b = 11 On parle alors de passage par valeur. Seule la valeur de la variable est transmise ` a la fonction, qui ne peut donc modier cette variable. Nous verrons que les pointeurs permettent des passages par adresse, an que la fonction puisse modier le contenu dune variable (voir chapitre 8).

7.1.5

Fonction main

La fonction main est particuli` ere. En eet, cest la seule fonction appell ee automatiquement lors du lancement du programme. Le programme doit donc en contenir une, et une seule. Ainsi, son en-t ete est-elle impos ee par le shell. Son interface est int main (int argc, char *argv[])

Comme toujours, les arguments sont des variables muettes. Ainsi, argc et argv peuvent prendre des noms di erents, mais les types sont x es. Le shell passe dailleurs des arguments bien pr ecis : largument char *argv[] d esigne un tableau de cha nes de caract` eres. Ce tableau contient donc plusieurs mots, tous les mots pass es sur la ligne de commande au moment du lancement du programme. Lespace servant de s eparateur. Ainsi, en lan cant > incrementation 10 La premi` ere case du tableau (argv[0]) contient incrementation, la deuxi` eme (argv[1]) contient 10. largument int argc d esigne la longueur du tableau (le nombre de mots sur la ligne de commande), soit 2.

7.2

R ecursivit e

Comme on la vu avec la fonction main qui appelle la fonction incrementation, toute fonction peut appeler toute autre fonction, ` a partir du moment o` u les types des arguments sont coh erents. Il nest dailleurs pas n ecessaire davoir d ej` a d eni la fonction que lon appelle, il sut que son prototype soit connu pour lutiliser. Il faudra cependant quelle soit compl` etement d enie quelque part au moment du link , la derni` ere phase de la compilation. Ainsi, les chiers den-t ete, tel que stdio.h contiennent uniquement les ent etes des fonctions usuelles, sans les corps.

E 7.2. RECURSIVIT

57

Par cons equent, rien nemp eche une fonction de sappeler elle-m eme, cest ce quon appelle une fonction r ecursive. Cette m ethode de programmation sera souvent pr ef er ee, en raison de la clart e et de la simplicit e des algorithmes quelle met en uvre. Cependant, il faut faire attention ` a ce quune telle fonction ne sappelle pas ind eniment : comme en math ematiques, une fonction r ecursive doit etre compl` etement d enie. Pour cela, il faut un (ou plusieurs) cas trivial qui ne fait pas appel ` a la r ecursivit e. En g en eral, le cas 0 ou le cas 1. Puis ensuite, on d enit le r esultat des valeurs sup erieures en fonction des valeurs inf erieures. Lexemple classique est le calcul de la factorielle (voir programme 16). fact.c #include <stdlib.h> #include <stdio.h> int factorielle(int n) { if (n == 1) return 1; return n*factorielle(n-1); } int main (int argc, char *argv[]) { int a,b; a = atoi(argv[1]); b = factorielle(a); printf("factorielle(%d) = %d\n",a,b); return 0; }

Programme 16: Factorielle (fact.c) Elle d enit une suite enti` ere par la r ecurrence : u1 = 1 un = n un1 pour n > 1 Il sagit alors dune fonction simplement r ecursive (et m eme avec r ecursivit e terminale, voir le cours dalgorithmique pour plus de d etails). Un autre exemple classique de fonction r ecursive, avec, cette fois-ci, une double r ecursivit e, est le calcul de la suite de Fibonacci (voir programme 17). En eet, elle d enit la suite enti` ere par la r ecurrence lin eaire dordre 2 suivante : v1 = 1 v2 = 1 vn = vn1 + vn2 pour n > 2

58

CHAPITRE 7. PROGRAMME STRUCTURE

fibo.c #include <stdlib.h> #include <stdio.h> int fibo(int n) { if ((n == 1)||(n == 2)) return 1; return fibo(n-1)+fibo(n-2); } int main (int argc, char *argv[]) { int a,b; a = atoi(argv[1]); b = fibo(a); printf("fibo(%d) = %d\n",a,b); return 0; }

Programme 17: Fibonacci (fibo.c) Cette notion de r ecursivit e sera etudi ee plus en d etail dans le cours dalgorithmique.

7.3
7.3.1

Les modules
Structure

Il est tr` es utile de d ecouper un programme en petites fonctions, an de r esoudre les di erents probl` emes un ` a un. De plus, cela permet de r eutiliser, ult erieurement dans un autre programme, des fonctions d ej` a ecrites. Pour cela, il peut etre bien de regrouper par modules les fonctions de m eme type. Le programme suivant de manipulation des complexes est ainsi d ecoup e en trois parties : la partie complexe.h (voir programme 18) qui est un chier dinclusion. Il contient la d eclaration des nouveaux types (et notamment des structures) et des fonctions, avec seulement le prototype, et le qualicatif extern. En eet, le prototype des fonctions sut au compilateur ` a savoir comment sinterface la fonction avec lext erieur : le type des arguments, et le type de sortie des fonctions. On y d eclare egalement les variables globales avec le qualicatif extern. Le second int er et de ce chier dinclusion est quil permet davoir, en un coup doeil, lensembles des types/fonctions d enies dans le module de d enition (voir le suivant module). le module complexe.c de d enition des fonctions (voir programme 19), avec par cons equent le contenu des corps des fonctions.

7.3. LES MODULES

59

complexe.h struct complexe_s { double reel; double imaginaire; }; typedef struct complexe_s complexe; extern complexe multiplication(complexe, complexe); extern void affichage(complexe); Programme 18: D eclaration des types et fonctions (complexe.h) le module principal (voir le programme 20) qui contient notamment la fonction main. Il fait linterface entre lutilisateur et les di erentes fonctions.

7.3.2

Compilation

La compilation dun tel programme peut se faire en plusieurs phases ou en une seule :

>gcc complexe.c complexe-main.c -o complexe

Ainsi, le compilateur fabrique les versions objet du chier complexe.c et du chier complexe-main.c puis edite les liens. Alors les appels aux fonctions sont eectivement branch es aux d enitions. Ce qui produit enn le chier ex ecutable auquel on donne le nom complexe. Lorsque les modules sont gros, et demandent beaucoup de temps ` a la compilation, il peut etre long de tout recompiler apr` es la modication dun seul module. On peut alors simplement recompiler le module en question puis editer les liens pour produire lex ecutable.

>gcc -c complexe.c >gcc -c complexe-main.c >gcc complexe.o complexe-main.o -o complexe

Lutilitaire make permettra lautomatisation de cette t ache : il ne lance la compilation que des modules modi es depuis la derni` ere compilation (voir la section 10.1).

60

CHAPITRE 7. PROGRAMME STRUCTURE

complexe.c #include <stdio.h> #include "complexe.h" complexe multiplication(complexe a, complexe b) { complexe c; c.reel = a.reel * b.reel - a.imaginaire * b.imaginaire; c.imaginaire = a.reel * b.imaginaire + a.imaginaire * b.reel; return c; } void affichage(complexe c) { printf("%g + i.%g",c.reel,c.imaginaire); } Programme 19: D enition des fonctions (complexe.c)

complexe-main.c #include <stdlib.h> #include <stdio.h> #include "complexe.h" int main (int argc, char *argv[]) { complexe c,d,e; c.reel = atof(argv[1]); c.imaginaire = atof(argv[2]); d.reel = atof(argv[3]); d.imaginaire = atof(argv[4]); e = multiplication(c,d); affichage(c);printf(" * "); affichage(d);printf(" = "); affichage(e);printf("\n"); return 0; } Programme 20: Module principal (complexe-main.c)

7.4. LE PREPROCESSEUR

61

7.4

Le pr eprocesseur

Comme nous lavons vu dans lintroduction, la premi` ere etape de la compilation fait appel au pr eprocesseur. Ce processus sert ` a envoyer, au compilateur, un chier source complet et consistant. Il fait donc un pr e-traitement du chier source.

7.4.1

Inclusions et d enitions

Le pr eprocesseur peut inclure des chiers ou remplacer des cha nes de caract` eres par dautres : #include <toto> dit au pr eprocesseur dins erer le chier standard toto. Le mot standard signiant quil doit aller le chercher parmi les chiers-syst` emes. #include "toto" dit au pr eprocesseur dins erer le chier toto qui se trouve dans le r epertoire courant. #define MAXIMUM 20 dit au pr eprocesseur de remplacer toutes les occurrences du mot MAXIMUM dans le programme par le mot 20. Ceci d enit donc des constantes. Il important de noter ici que ces commandes transmises au pr eprocesseur ne sont pas des instructions du langage C. En eet, elles ne se terminent pas par un ;. Notamment, pour la commande #define, il faut la d ecomposer en : #define NOM n de ligne Alors, le pr eprocesseur remplacera toutes les occurrences de NOM par la n de la ligne (y compris un eventuel signe de ponctuation). Une erreur dans cette n de ligne sera signal ee, par le compilateur, aux occurrences de NOM, et non pas ` a cette ligne de d enition. On peut de la m eme mani` ere d enir des macros. Ainsi #define moyenne(A,B) (A+B)/2

d enit la macro moyenne. Toutes les occurrences de moyenne(x,y), ind ependamment des arguments, seront remplac ees par lexpression compl` ete du calcul de la moyenne. Certains motiveront cette utilisation, par rapport ` a lutilisation dune fonction, pour optimiser le code. En eet, cela ne n ecessite pas dappel ` a fonction, assez co uteux. Mais en contre-partie, le chier ex ecutable sera plus volumineux. Ceci peut etre tr` es p enalisant : si lex ecutable est petit, il tient dans la m emoire cache du processeur est sex ecute beaucoup plus vite. Aussi, mieux vaut-il laisser loptimiseur de code se charger de loptimisation. En eet, les optimiseurs sont de plus en plus performants ! Ainsi, la seule motivation des macros est la lisibilit e. Pour de petites op erations, les macros sont plus concises que les fonctions. #undef MAXIMUM dit au pr eprocesseur doublier une pr ec edente d enition (constante ou macro)

62

CHAPITRE 7. PROGRAMME STRUCTURE

7.4.2

Compilation conditionnelle

Dans la phase de d eboguage, ou pour permettre la compilation sur di erentes platesformes, on peut vouloir compiler telle ou telle partie en fonction de certains crit` eres : en fonction dune constante #if TOTO part 1 #else part 2 #endif si TOTO est non nulle (vraie), la partie 1 est ins er ee et la partie 2 supprim ee. Sinon, cest le contraire. La directive #else nest pas indispensable. en fonction de la d enition dune constante #ifdef LINUX part 1 #else part 2 #endif si LINUX a et e d enie (par un #define par exemple, non suivi dun #undef !), la partie 1 est ins er ee et la partie 2 supprim ee. Sinon, cest le contraire. La directive #else nest pas indispensable. en fonction de la non-d enition dune constante #ifndef MSDOS part 1 #else part 2 #endif si MSDOS nest pas d enie (pas de #define, ou alors un #undef !), la partie 1 est ins er ee et la partie 2 supprim ee. Sinon, cest le contraire. La directive #else nest pas indispensable.

7.4.3

Le pr eprocesseur gcc

Il est egalement possible de d enir des constantes ou des macros sur la ligne de commande au moment de la compilation :

>gcc -DTOTO=10 hello.c -o hello >gcc -DLINUX prog.c -o prog

7.4. LE PREPROCESSEUR

63

Ainsi, lors de la compilation de hello.c, la constante/macro TOTO est d enie ` a 10. Lors de la compilation de prog.c, la constante/macro LINUX est d enie (par d efaut ` a 1).

64

CHAPITRE 7. PROGRAMME STRUCTURE

Chapitre 8 Les pointeurs, les tableaux et les structures

Sommaire
8.1 Pointeurs . . . . . . . . . 8.1.1 D enition . . . . . . . 8.1.2 Utilisation . . . . . . . 8.1.3 Passage par adresse . 8.2 Tableaux . . . . . . . . . . 8.3 Allocation dynamique de 8.4 Les structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . m emoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 65 66 66 67 67 68

Les pointeurs sont une notion d elicate mais indispensable ` a ma triser pour utiliser correctement les structures, les tableaux, ou faire des passages par adresse dans des fonctions (an que ces fonctions puissent modier la variable pass ee en argument). De plus, ils seront ` a la base de tous les algorithmes et structures etudi es en algorithmique (listes, arbres, graphes, etc).

8.1
8.1.1

Pointeurs
D enition

Comme on la d ej` a vu dans le chapitre sur les types (voir chapitre 2), un pointeur contient une adresse m emoire. Cette adresse pointe alors sur on objet, qui d epend de la d eclaration du pointeur. En eet, les pointeurs peuvent etre typ es, an de g erer les tableaux correctement. De plus, en passant un tel pointeur comme argument dune fonction, il est alors possible a la fonction de modier le contenu de la variable point ` ee par ce pointeur. En eet, utilis ee seule, la variable pass ee en argument ne peut etre modi ee (le pointeur) car la fonction travaille sur une copie, mais ce sur quoi elle pointe nest pas transf er e.

66

CHAPITRE 8. LES POINTEURS, LES TABLEAUX ET LES STRUCTURES

8.1.2

Utilisation

Il existe deux op erateurs unaires li es aux pointeurs (voir gure 5.1, page 41) : lop erateur de contenu dune adresse ; si ptint est un pointeur de type entier, *ptint vaut lentier contenu ` a ladresse ptint. lop erateur d adresse dune variable ; si a est une variable quelconque, &a vaut ladresse ` a laquelle est stock ee la variable a.

8.1.3

Passage par adresse

Nous avons d ej` a eu ` a faire au passage par adresse dans le chapitre sur les entr ees-sorties (voir chapitre 4), notamment avec la fonction scanf. En eet, cette fonction scanne une cha ne de caract` eres puis extrait certaines parties pour les stocker dans des variables ` la sortie de la fonction, le contenu de ces variables doit pass ees comme arguments. A r eellement etre la valeur introduite par la fonction, il doit rester modi e ! Cest pour cela que lon donne, non pas la valeur de la variable ` a modier, mais son adresse, en utilisant lop erateur unaire dadresse &a (voir programme 8, page 36, et gure 4.2, page 38), qui permet la modication du contenu point e. Ainsi, on peut modier le programme 15 comme pr esent e dans le programme 21. Ce dernier modie le contenu de la variable, dont le pointeur est pass e comme argument.

auto-incrementation.c #include <stdio.h> #include <stdlib.h> void incrementation(int *ptx) { (*ptx)++; } int main (int argc, char *argv[]) { int a; a = atoi(argv[1]); incrementation(&a); printf("a = %d\n",a); return 0; }

Programme 21: Auto-Incr ementation (auto-incrementation.c)

8.2. TABLEAUX

67

8.2

Tableaux

Un tableau est en fait un pointeur sur une zone m emoire o` u sont stock ees toutes les cases, de fa con cons ecutive (voir gure 8.1). Ainsi, gr ace au typage du pointeur, pour un
t[0] int t[N]; t t[1] t[2] t+1 t[3] ... t+3

Fig. 8.1 Tableau dentiers tableau int t[N], de longueur N : t est un pointeur sur la premi` ere case du tableau, par cons equent, t[0] et *t d esignent tous les deux le contenu de la premi` ere case du tableau ; t+1 est donc un pointeur sur la deuxi` eme case du tableau, par cons equent, t[1] et *(t+1) d esignent tous les deux le contenu de la deuxi` eme case du tableau ; t+i est, de fa con g en erale, un pointeur sur la i + 1-i` eme case du tableau, par cons equent, t[i] et *(t+i) d esignent tous les deux le contenu de la i + 1-i` eme case du tableau. En eet, le typage du pointeur permet de d enir correctement le pointeur t+1. Ce pointeur nest pas ladresse t plus un, mais ladresse t plus la taille dun entier. Dans lautre sens, il est possible dobtenir ladresse dune case du tableau ` a laide de la commande & : &t[0] est le pointeur sur la premi` ere case du tableau. Il sagit donc de t ; &t[i] est le pointeur sur la i + 1-i` eme case du tableau. Il sagit donc de t+i. &t[i]-j est le pointeur sur la i j + 1-i` eme case du tableau. Il sagit donc de t+i-j . Comme on la vu dans la section sur les tableaux, la d eclaration dun tableau ne peut faire intervenir quune constante. Ainsi, la taille dun tableau est x ee par le programme, lors de la compilation. Heureusement, il est possible d allouer dynamiquement la place n ecessaire au stockage des cases dun tableau.

8.3

Allocation dynamique de m emoire

Etant donn e un pointeur, il est possible de le faire pointer vers une zone m emoire de taille d enie dynamiquement au cours de lex ecution du programme : void *calloc(size_t nmember, size_t size) alloue la m emoire n ecessaire pour un tableau de nmember el ements, chacun etant de taille size octets. Chaque case est initialis ee ` a z ero. Il retourne le pointeur sur cette zone m emoire. Pour obtenir la taille de lobjet que lon souhaite stocker dans chaque case, et comme la taille dun entier ou dun ottant nest pas standardis ee, on utilise la commande sizeof.

68

CHAPITRE 8. LES POINTEURS, LES TABLEAUX ET LES STRUCTURES

int n = 15; double *t; t = calloc (n, sizeof(double)); void *malloc(size_t size) alloue size octets de m emoire. Son usage est semblable ` a celui de calloc, mais les octets ne sont pas initialis es (encore moins ` a 0).

int n = 15; double *t; t = malloc (n*sizeof(double)); Le type void * est appel e pointeur g en erique. Ce type est automatique remplac e par le type pointeur eectif d` es que possible. Le programme 22 pr esente une impl ementation di erente du calcul des el ements de la suite de Fibonacci de fa con plus ecace. Elle utilise un tableau. Cependant, la taille de ce tableau nest pas connue ` a lavance puisquelle d epend de lindice de l el ement de la suite que lon cherche ` a calculer. ` A la n de la fonction fibo, la variable locale t dispara t, mais la m emoire allou ee dynamiquement reste r eserv ee. Ainsi, lors dune nouvelle allocation de m emoire, cette m emoire ne sera pas consid er ee disponible, alors quelle est devenue inutilisable (le seul moyen dy acc eder etait le pointeur t). De cette fa con, tr` es rapidement, il ny a plus de m emoire disponible ! Pour eviter cela, on lib` ere la m emoire qui nest plus n ecessaire avec la commande free ex ecut ee sur le pointeur qui d esigne lespace m emoire en question :

free(t);

Remarque : Il est egalement possible daugmenter la taille dun tableau avec la commande realloc, lorsque le tableau initial sav` ere trop petit. Mais cela revient ` a allouer de la m emoire ailleurs et ` a d eplacer les premi` eres cases au d ebut de ce nouveau tableau. En eet, il ny a aucune raison qu` a la suite du tableau initial, un espace m emoire susant soit disponible.

8.4

Les structures

Comme on la vu dans le chapitre 2 sur les types, il est possible de d enir des types elabor es (voir le programme 4). On donne alors un nom plus simple ` a la structure et ` a un pointeur sur une telle structure :

8.4. LES STRUCTURES

69

fibo-tableau.c #include <stdio.h> #include <stdlib.h> int fibo(int n) { int i,f; int *t; t = malloc (n*sizeof(int)); t[0] = 1; t[1] = 1; for (i=2; i<n; i++) t[i] = t[i-1] + t[i-2]; f = t[n-1]; free(t); return f; } int main (int argc, char *argv[]) { int a,b; a = atoi(argv[1]); b = fibo(a); printf("fibo(%d) = %d\n",a,b); return 0; }

Programme 22: Suite de Fibonacci tableau (fibo-tableau.c)

struct ma_structure { int nombre; float valeur; }; typedef struct ma_structure St; typedef struct ma_structure *ptSt;

Le type struct ma_structure, ou St, regroupe alors deux champs, un entier et un ottant. Un objet st de type St contient ces deux valeurs dans ses deux champs d enomm es st.nombre et st.valeur.

70

CHAPITRE 8. LES POINTEURS, LES TABLEAUX ET LES STRUCTURES

En revanche, si un objet ptst est un pointeur sur une telle structure, et par cons equent de type (struct ma_structure *), ou simplement ptSt, avant de remplir les champs de la structure, il faut allouer la m emoire pour stocker cette structure :

ptSt ptst; ptst = malloc(sizeof(St));

Enn, le pointeur ptst pointe sur une telle structure qui contient donc deux champs d enomm es (*ptst).nombre et (*ptst).valeur, ou plus simplement ptst->nombre et ptst->valeur.

ptSt->nombre = 10; ptSt->valeur = 105.1045;

Un exemple, avec les listes, est pr esent e dans le chapitre sur les structures dynamiques (voir le programme 23, page 74).

Chapitre 9 Les structures dynamiques

Sommaire
9.1 9.2 9.3 Structure de liste . . . . . . . . . . . . . . . . Impl ementation des listes cha n ees . . . . . . Extensions . . . . . . . . . . . . . . . . . . . . . 9.3.1 Listes doublement cha n ees . . . . . . . . . . 9.3.2 Arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 72 72 72 73

Comme nous lavons vu dans le chapitre pr ec edent, les tableaux permettent de stocker de grandes quantit es de donn ees de m eme type. Mais, m eme sil est possible dagrandir un tableau une fois plein (ou constat e trop petit), ceci consiste en une op eration co uteuse ` (r eallocation, copie, etc). A ce genre ce structure, on pr ef` ere souvent les structures dynamiques, qui grossissent selon les besoins. Ainsi, seule la place n ecessaire est r eserv ee. Un bon exemple qui sera vu plus en d etail dans le cours dalgorithmique est la structure de liste cha n ee.

9.1

Structure de liste

Une liste cha n ee est un cha nage de cellules. Une cellule est constitu ee de deux champs : le champ de valeur (appel e val), qui stockera les donn ees utiles, seules vues de lext erieur, et le champ dadressage de la cellule suivante (appel e next), tel que pr esent e sur la gure 9.1. La n de la liste est d esign ee par une cellule particuli` ere, appel ee usuellement nil.
Cellule Liste val 13 next

10

nil

Fig. 9.1 Liste cha n ee

72

CHAPITRE 9. LES STRUCTURES DYNAMIQUES

Cette structure de liste est tr` es riche. Cest pour cela quelle est tr` es etudi ee en algorithmique. Il existe bien entendu plusieurs moyens pour limpl ementer, qui d ependent notamment du langage utilis e.

9.2

Impl ementation des listes cha n ees

Nous pr esentons, dans le programme 23, une impl ementation usuelle des listes cha n ees en C. Tout dabord, la cellule est d enie par la structure struct cellule_s que nous renommons aussit ot (par soucis de clart e) cellule. Cette structure de cellule contient deux champs, un de type entier pour stocker les donn ees utiles, puis un de type pointeur sur une cellule, pour pointer sur la cellule suivante. Ensuite, nous d enissons le type list en tant que tel : un pointeur sur une cellule. Puis nous d esignons la n de liste (ou la liste vide, egalement not ee nil) par le pointeur NULL. Il sagit dune constante C aect ee ` a 0. Une fois que le type liste est compl` etement d eni, nous pouvons d enir des fonctions pour agir sur ce type. Les fonctions classiques sur les listes sont : list cons(int a, liste l) qui ajoute l el ement a en t ete de la liste l, et retourne la liste r esultat. Pour cela, il faut cr eer une nouvelle cellule dans laquelle on d enit la valeur ` a a et ladresse de la cellule suivante ` a l. La liste r esultante est la liste d enie par le pointeur sur cette nouvelle cellule. int head(list l) qui retourne la valeur dans la cellule de t ete de la liste l. list tail(list l) qui retourne la queue de la liste l. Cest-` a-dire la liste l priv ee de sa cellule de t ete. Ces deux fonctions ne sont pas d enies si l est la liste vide. On ne se pr eoccupera pas de ces cas. En eet, on pourrait g erer ces cas particuliers, appel ees exceptions, mais le langage C ne permet pas de le faire naturellement (contrairement au langage Java). Alors, on pourrait faire un exit(0) pour quitter le programme dans de tels cas. Lentier pass e en argument, d enissant le statut r ecup er e par le shell, peut pr eciser le type derreur rencontr e.

9.3
9.3.1

Extensions
Listes doublement cha n ees

Une extension classique des listes cha n ees est la liste doublement cha n ee. En eet,
previous next

Cellule Liste

val 13

nil

10

nil

Fig. 9.2 Liste doublement cha n ee

9.3. EXTENSIONS

73

la structure de liste simplement cha n ee, comme vue dans les sections pr ec edentes, ne permettent que de descendre le long de la liste. Elle impl emente ainsi parfaitement la notion de pile (dite aussi liste LIFO, voir le cours dalgorithmique). Mais alors, lire le contenu de la derni` ere cellule est tr` es long. Pour combler cette d efaillance, et si aller chercher la derni` ere cellule est une op eration courante ` a eectuer (telle que dans une le ou liste FIFO), on impl emente la liste avec une liste doublement cha n ee (voir la gure 9.2).

9.3.2

Arbres

Une autre extension naturelle des listes simples, o` u chaque cellule pointe sur la suivante, est de faire pointer une cellule sur plusieurs autres. Si chaque cellule pointe sur z ero, une ou deux cellules, on parle darbres binaires (voir la gure 9.3). Si le nombre est variable, on parle darbres g en eraux. Ces notions seront vues en d etail dans le cours dalgorithmique. Leur impl ementation fera naturellement appel aux structures (cellule, ou nud pour les arbres) et aux pointeurs.
Noeud val Arbre binaire 10

5 left right

13

nil

nil

18

nil

nil

nil

nil

Fig. 9.3 Arbres binaires

74

CHAPITRE 9. LES STRUCTURES DYNAMIQUES

liste.c #include <stdio.h> #include <stdlib.h> typedef struct cellule_s { int val; struct cellule_s *next; } cellule; typedef cellule *list; list nil = NULL; list cons (int a, list l) { list l1; l1 = malloc (sizeof(cellule)); l1->val = a; l1->next = l; return l1; } int head (list l) { return l->val; }

list tail (list l) { return l->next; } void affiche(list l) { if (!l) printf("nil \n"); else { printf("%d -> ",head(l)); affiche(tail(l)); } } int main (int argc, char *argv[]) { list l = nil; affiche(l); l = cons(10,l); l = cons(13,l); affiche(l); return 0; }

Programme 23: Listes cha n ees (liste.c)

Chapitre 10 Lenvironnement sous UNIX


Sommaire
construction sur mesure : make . . . . . . Fichier de Conguration : Makefile . . . . . Wildcards et D ependances . . . . . . . . . . . Constantes et Variables . . . . . . . . . . . . Cibles Fictives . . . . . . . . . . . . . . . . . Invocation de la Commande make . . . . . . . gestion des versions : cvs . . . . . . . . . Cr eation dun projet . . . . . . . . . . . . . . 10.2.1.1 En partant de rien ! . . . . . . . . . 10.2.1.2 En partant dun projet commenc e . 10.2.2 Fichier dinformation . . . . . . . . . . . . . . 10.2.3 Modications de la structure . . . . . . . . . 10.2.3.1 Ajout de chier/R epertoire . . . . . 10.2.3.2 Suppression de chier/r epertoire . . 10.2.3.3 Modication eective . . . . . . . . 10.2.4 Int egration des modications . . . . . . . . . 10.2.5 Gestion des versions . . . . . . . . . . . . . . 10.2.6 Commentaires . . . . . . . . . . . . . . . . . 10.3 Le d ebogueur : gdb . . . . . . . . . . . . . . . . 10.3.1 Lancement du d ebogueur . . . . . . . . . . . 10.3.2 Commandes de base . . . . . . . . . . . . . . 10.3.2.1 run . . . . . . . . . . . . . . . . . . 10.3.2.2 where . . . . . . . . . . . . . . . . . 10.3.2.3 up . . . . . . . . . . . . . . . . . . . 10.3.2.4 breakpoints . . . . . . . . . . . . . 10.3.2.5 continue . . . . . . . . . . . . . . . 10.3.2.6 step . . . . . . . . . . . . . . . . . . 10.3.2.7 next . . . . . . . . . . . . . . . . . . 10.3.2.8 print . . . . . . . . . . . . . . . . . 10.3.2.9 display . . . . . . . . . . . . . . . 10.1 Une 10.1.1 10.1.2 10.1.3 10.1.4 10.1.5 10.2 Une 10.2.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 76 77 77 78 78 80 80 80 80 80 80 80 81 81 81 81 81 82 82 82 82 82 83 83 83 83 83 83 84

76

CHAPITRE 10. LENVIRONNEMENT SOUS UNIX

10.1

Une construction sur mesure : make

Lorsquun programme est constitu e de plusieurs modules, il nest pas n ecessaire de tout recompiler apr` es la modication dune seule partie. Nous avons donc vu dans la partie sur la programmation structur ee, et notamment sur les modules (voir section 7.3), quil etait possible de compiler s epar ement chaque module, puis ensuite editer les liens :

>gcc -c complexe.c >gcc -c complexe-main.c >gcc complexe.o complexe-main.o -o complexe

Il est possible dautomatiser la re-compilation de tout (et seulement) ce qui est n ecessaire, avec loutil make. Cet outil est tr` es performant, et tr` es complexe. Nous allons pr esenter les fonctions essentielles permettant de mener ` a bien et ais ement un projet comportant plusieurs modules.

10.1.1

Fichier de Conguration : Makefile

La commande make utilise un chier de conguration . Il va chercher, par d efaut, dans le r epertoire courant, le chier de conguration GNUmakefile, makefile puis Makefile. Les deux derniers etant pr ef erables, puis surtout Makefile, car il appara tra ainsi g en eralement en t ete du ls. Ce chier de conguration d ecrit comment chaque cible , ou objectif ` a atteindre ou ` a cr eer, peut etre obtenue en fonction des chiers sources (initialement existants). Il pr ecise egalement les d ependances des chiers entre eux. Le chier pr esent e programme 24 fournit un exemple, bas e sur la structure suivante :

<cible> : <source> <-tab-> ACTION

Remarque : Il est important de noter que le blanc devant la commande ` a eectuer est une tabulation (et non une s erie despaces). Lex ecutable complexe n ecessite les objets complexe.o et complexe-main.o pour l edition des liens. Chacun etant obtenu ` a partir du .c correspondant. Loutil make regarde si les sources ont et e modi ees ` a une date ult erieure ` a la date de cr eation de la cible. Ainsi, si le chier complexe.o est plus ancien que le chier complexe.c ou complexe.h, ce qui signie quun de ces derniers a et e modi e depuis la derni` ere compilation, complexe.o sera re-compil e. Puis, r ecursivement, complexe deviendra obsol` ete, et sera donc reconstruit.

10.1. UNE CONSTRUCTION SUR MESURE : MAKE

77

Makefile1 complexe : complexe.o complexe-main.o gcc complexe.o complexe-main.o -o complexe complexe.o : complexe.c complexe.h gcc -c complexe.c complexe-main.o : complexe-main.c complexe.h gcc -c complexe-main.c

Programme 24: Exemple de chier Makefile (Makefile1)

10.1.2

Wildcards et D ependances

Au lieu de donner la liste de tous les .o avec leurs .c et .h associ es et la commande pour passer de lun ` a lautre, on peut simplement dire comment on obtient tout objet .o a partir de son .c. `

%.o : %.c gcc -c $<

Dans cet exemple ; %.o est toute cible .o, produite ` a partir du m eme nom avec suxe .c. Le nom exact de la source est stock e dans la variable < (appel ee par $<) et le nom exact de la cible est stock e dans la variable @ (appel ee par $@), voir la section suivante sur les variables. Puis on pr ecise la liste des d ependances, cest-` a-dire la liste des chiers dont d ependent les objets ` a cr eer, et dont les dates de modication sont ` a contr oler :

complexe.o : complexe.c complexe.h complexe-main.o : complexe-main.c complexe.h

Le chier Makefile2 (voir programme 25) pr esente alors une version equivalente mais plus compacte du pr ec edent chier.

10.1.3

Constantes et Variables

Il est possible dutiliser des variables dont le contenu pourra etre utilis e par linvocation de la variable :

78

CHAPITRE 10. LENVIRONNEMENT SOUS UNIX

Makefile2 complexe : complexe.o complexe-main.o gcc complexe.o complexe-main.o -o complexe %.o : %.c gcc -c $< complexe.o : complexe.c complexe.h complexe-main.o : complexe-main.c complexe.h

Programme 25: Makele : version compacte (Makefile2)

OBJETS = complexe.o complexe-main.o complexe : $(OBJETS) gcc $(OBJETS) -o complexe

10.1.4

Cibles Fictives

Certaines cibles peuvent ne pas donner lieu ` a la cr eation dun chier. On parle alors de cible ctive . Alors la commande associ ee sera toujours eectu ee puisque make constate que le chier nexiste pas. Cela est utilis e couramment pour deux actions essentielles : d enir une action par d efaut. do : complexe pour donner des noms simples ` a des actions importantes ou souvent invoqu ees, tel que le nettoyage. clean : rm -f $(OBJETS) complexe

10.1.5

Invocation de la Commande make

Au lancement de la commande make, sans aucun argument, loutil cherche le chier de conguration (Makefile) puis cherche ` a produire la premi` ere cible. Cest pour cela quil est conseill e de mettre une cible ctive par d efaut en premier (mais pas la cible clean). Si lon souhaite ex ecuter make sur un chier de conguration particulier, on utilise loption -f :

10.1. UNE CONSTRUCTION SUR MESURE : MAKE

79

> make -f monmakefile Si lon souhaite ex ecuter make en d enissant une nouvelle variable, ou en modiant le contenu dune variable existante, on fait la d enition en argument de la commande make : > make OBJETS=toto.o En eet, cette variable sera alors d ej` a d enie avant la lecture du chier de conguration, et la simple ligne

OBJETS = complexe.o complexe-main.o

ne modie pas une variable d ej` a d enie. Pour d enir ` a nouveau une variable d ej` a d enie, il faut le pr eciser avec la commande override. Enn, pour demander lex ecution (si besoin) de la commande associ ee ` a une cible pr ecise, on passe cette cible sur la ligne de commande. Ainsi, le Makefile classique pour un projet C est de la forme pr esent ee dans le programme 26.

Makefile3 GCC = gcc -O OBJETS = complexe.o complexe-main.o do : complexe %.o : %.c $(GCC) -c $< complexe : $(OBJETS) $(GCC) $(OBJETS) -o complexe clean : rm -f $(OBJETS) complexe core *~ complexe.o : complexe.c complexe.h complexe-main.o : complexe-main.c complexe.h

Programme 26: Makele : classique C (Makefile3) Son utilisation est alors > make -f Makefile3 pour cr eer lex ecutable et > make -f Makefile3 clean pour faire le m enage .

80

CHAPITRE 10. LENVIRONNEMENT SOUS UNIX

10.2

Une gestion des versions : cvs

Lors de gros projets, on aime garder les versions stables successives, an de revenir en arri` ere en cas de d ecouverte de bogues. On aime aussi avoir un historique des di erentes etapes. Puis enn, si on travaille ` a plusieurs sur ce projet, les mises ` a jours ne sont pas ais ees. Lutilitaire cvs (Concurrent Versions Control) fait tout cela pour vous ! Il y a donc une base, un r epertoire accessible par tous les utilisateurs du projet, eventuellement sur une machine distante, dans laquelle seront stock ees les di erentes versions. Ce r epertoire est d eni par la variable syst` eme CVSROOT : > setenv CVSROOT=$HOME/cvsroot ce r epertoire est alors cr e e et initialis e par la commande > cvs init

10.2.1
10.2.1.1

Cr eation dun projet


En partant de rien !

Nous voulons commencer un nouveau projet, avec une gestion des versions. Pour cela, il faut cr eer le(s) r epertoire(s) chez soi > mkdir newproject puis, alors, cr eer le r epertoire correspondant dans la base centrale > cd newproject > cvs import -m "Cr eation du r epertoire" newproject projet start 10.2.1.2 En partant dun projet commenc e

Nous voulons g erer les versions dun projet d ej` a commenc e. Pour cela, il faut ins erer tous les chiers existants dans la base centrale. Une fois dans le r epertoire contenant le projet en cours, > cvs import -m "Insertion des fichiers" newproject projet start

10.2.2

Fichier dinformation

Pour cr eer le r epertoire CVS dans le r epertoire du projet en cours, taper > cd .. > cvs checkout newproject Maintenant, les ajouts, modications, suppressions de chiers et gestion de versions peuvent commencer.

10.2.3
10.2.3.1

Modications de la structure
Ajout de chier/R epertoire

Pour ajouter un el ement (chier ou r epertoire) ` a la liste de ceux g er es par cvs, par exemple Makefile, on tape > cvs add Makefile Cet ajout sera eectif lors de la prochaine mise ` a jour de la base.

10.2. UNE GESTION DES VERSIONS : CVS

81

10.2.3.2

Suppression de chier/r epertoire

Pour supprimer un el ement (chier ou r epertoire) ` a la liste de ceux g er es par cvs, par exemple Makefile.old, on tape > cvs remove Makefile.old Cette suppression sera eective lors de la prochaine mise ` a jour de la base. 10.2.3.3 Modication eective

Les modications ci-dessus, puis les modications des contenus des chiers sont locales. Pour les rendre eectives dans la base, et donc accessibles ` a tous, il faut faire > cvs commit Cette op eration modiera la base. Remarque : Il faut remarquer que quelquun peut avoir modi e un chier sur lequel vous avez travaill e. Ainsi, cette op eration peut rencontrer des conits. Cependant, cvs tente de rep erer les lignes modi ees par chaque utilisateur, et de faire les mises ` a jour au mieux. Si cvs ne sait pas g erer le conit rencontr e, il vous demande de laide. Pour eviter au maximum ces conits, il sut de souvent synchroniser les r epertoires (personnel et base de cvs) avec commit pour mettre ` a jour la base de cvs, et update pour mettre ` a jour son r epertoire personnel (voir ci-dessous).

10.2.4

Int egration des modications

Comme pr ecis e ci-dessus, ce gestionnaire de versions permet le suivi de projet par plusieurs utilisateurs. Il faut donc mettre ` a jours son propre r epertoire en fonction des mises jour de la base par les autres programmeurs (pour eviter au maximum les conits). Pour cela, avant de se mettre au travail, on met ` a jour sa base de travail personnelle > cvs update

10.2.5

Gestion des versions

Cet utilitaire permet de g erer les versions. Par d efaut, les chiers commencent avec un num ero de version 1.1. Lorsque le projet a atteint un etat satisfaisant, on le ge dans un nouveau num ero de version > cvs commit -r2.0 Ainsi, l etat actuel est r epertori e dans le num ero de version 2.0. ` tout moment, il est possible de r A etablir un version ancienne : > cvs checkout -r1.1 cr ee le r epertoire avec les chiers dans l etat dorigine (version 1.1), o` u on le souhaite, apr` es avoir supprim e notre propre version par exemple.

10.2.6

Commentaires

Lors de la plupart des op erations, des commentaires peuvent etre ins er es. Ils appara tront dans les log : > cvs log Makefile

82

CHAPITRE 10. LENVIRONNEMENT SOUS UNIX

Soit ces commentaires sont mis sur la ligne de commande, par linterm ediaire du param` etre -m, comme pr esent e dans les exemples de cvs import ci-dessus, soit un editeur de texte est lanc e an que vous saisissiez ces commentaires avant dachever la mise ` a jour.

10.3

Le d ebogueur : gdb

Un utilitaire bien pratique pour r esoudre des probl` emes de programmation apparemment insolubles , le d ebogueur. Il permet de nombreuses op erations, nous allons voir les essentielles. Il faut cependant remarquer quune aide en ligne r epond ` a la plupart des questions, en posant la question help, suivie eventuellement de la commande sur laquelle on souhaite des d etails.

10.3.1

Lancement du d ebogueur

Pour utiliser le d ebogueur, il faut compiler le programme avec les symboles de d eboguage. Pour cela, on ajoute le param` etre -g > gcc -g hello.c -o hello Ensuite, on le lance sur la ligne de commande, avec > gdb hello Mais cette utilisation est beaucoup moins conviviale que sous emacs. En eet, sous emacs, il est possible davoir une ` eche qui indique lendroit de lex ecution dans le chier C. Pour lancer le d ebogueur sous emacs, on tape Alt-X gdb. Puis ` a la question suivante, on saisie le nom de lex ecutable.

10.3.2

Commandes de base

Dans chacune des commandes ci-dessous, il est possible de ne saisir que le d ebut de chaque mot, si aucune ambigu te ne survient : r pour run, b pour breakpoints, etc. 10.3.2.1 run

On peut bien entendu lancer lex ecution du programme ` a d eboguer avec run. Si le programme ne provoque pas de d ebordement (erreur fatale), il se termine normalement, sinon il termine avec un

Program received signal SIGSEGV, Segmentation fault. 0x80483b3 in main () at segmentation.c:5

avec le programme 27 qui acc` ede ` a de la m emoire non allou ee. 10.3.2.2 where

La commande where pr ecise la position dans la pile dex ecution, ce qui permet de savoir dans quel appel de fonction on se trouve.

: GDB 10.3. LE DEBOGUEUR

83

segmentation.c #include <stdio.h> int main () { int *tab=NULL; tab[10]=5; return 0; }

Programme 27: D ebordement (segmentation.c) 10.3.2.3 up

La commande up fait monter dun cran dans la pile dex ecution, ce qui permet de savoir o` ua et e fait lappel de fonction dans laquelle on se trouve. 10.3.2.4 breakpoints

Il est possible de positionner des points darr et an dobliger larr et de lex ecution du programme ` a un endroit pr ecis, en donnant le num ero de la ligne :

breakpoints 4

10.3.2.5

continue

Cela relance lex ecution jusquau prochain point darr et (ou n de programme). 10.3.2.6 step

Ex ecute la ligne ech ee, et stoppe lex ecution. On descend alors, si n ecessaire, dans la fonction appel ee pour stopper lex ecution au d ebut de cette fonction. 10.3.2.7 next

Ex ecute la ligne ech ee, et stoppe lex ecution sur la ligne suivante dans le programme. En cas dappel ` a une fonction, cette fonction est totalement ex ecut ee avant larr et de lex ecution. 10.3.2.8 print

Permet dacher ponctuellement le contenu dune variable

84

CHAPITRE 10. LENVIRONNEMENT SOUS UNIX

print tab

ache le contenu de la variable tab, si cette derni` ere est d enie. 10.3.2.9 display

Ache le contenu dune variable ` a tout arr et de lex ecution.

Chapitre 11 Quelques compl ements

Sommaire
11.1 Les cha nes de caract` eres . . . . . . . . . . . . . . . 11.1.1 Structure dune cha ne de caract` eres . . . . . . . . 11.1.2 Quelques commandes sur les cha nes de caract` eres 11.2 Gestion des chiers . . . . . . . . . . . . . . . . . . 11.2.1 Type chier . . . . . . . . . . . . . . . . . . . . . . 11.2.2 Cr eation dun chier . . . . . . . . . . . . . . . . . 11.2.3 Lecture/Ecriture . . . . . . . . . . . . . . . . . . . 11.2.4 Fin de chier . . . . . . . . . . . . . . . . . . . . . 11.2.5 Cl oture . . . . . . . . . . . . . . . . . . . . . . . . 11.3 C 99 . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.4 La biblioth` eque standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 85 85 88 88 88 89 89 89 89 90

Dans ce chapitre, nous allons regrouper un certain nombre de renseignements utiles, telle que la manipulation des cha nes de caract` eres et des chiers. Leurs descriptions plus compl` etes pourront etre trouv ees avec un appel au man (ex : man strlen).

11.1
11.1.1

Les cha nes de caract` eres


Structure dune cha ne de caract` eres

Une cha ne de caract` eres est en fait un tableau de caract` eres. La n de la cha ne est d esign ee par le caract` ere \0. Il sagit donc aussi dun pointeur sur un caract` ere (char *). Mais des fonctions particuli` eres permettent de manipuler ces tableaux de caract` eres plus simplement que des tableaux quelconques. Le programme 28 en regroupe certaines.

11.1.2

Quelques commandes sur les cha nes de caract` eres

Des commandes permettent de d eterminer la longueur dune cha ne, de comparer deux cha nes, de copier le contenu de lune dans lautre ou de concat ener deux cha nes :

86

CHAPITRE 11. QUELQUES COMPLEMENTS

palindrome.c #include <stdio.h> #include <string.h> int palindrome(char *s) { char s1[80]; int i,l = strlen(s); for (i=0; i<l; i++) s1[i] = s[l-i-1]; s1[l] = \0; return (!strcmp(s,s1)); } int main (int argc, char *argv[]) { char s[80]; int t; strcpy (s,argv[1]); t = palindrome(s); if (t) printf("%s est un palindrome\n",s); else printf("%s nest pas un palindrome\n",s); return 0; }

Programme 28: Palindrome (palindrome.c) strlen, qui retourne la longueur de la cha ne (sans le \0 nal) ; strcmp et strncmp, qui comparent le contenu de deux cha nes de caract` eres. La commande strcmp(s1,s2) retourne un nombre n egative, nul ou positif selon que s1 est plus petit, egal, ou sup erieur ` a s2. La commande strncmp(s1,s2,n) fait la m eme chose, mais en ne consid erant que les n premiers caract` eres de s1 ; strcpy et strncpy, qui copient le contenu dune cha ne de caract` eres dans une autre. La commande strcpy(s1,s2) copie la cha ne s2 dans la cha ne s1, ` a condition que la longueur de s1 (nombre de cases du tableau de caract` eres allou ees) est susante. La commande strncpy(s1,s2,n) fait la m eme chose, mais en ne copiant que les n premiers caract` eres de s2 ; strcat et strncat, qui fonctionne comme les deux fonctions pr ec edentes, ` a la di erence que la cha ne s2 est concat en ee ` a la suite de la cha ne s1 (si la place n ecessaire est disponible). Remarque : pour ces quatre derni` eres commandes strcpy et strncpy puis strcat et strncat, la cha ne r eceptrice doit etre allou ee, de taille susante, sous peine, soit dune

` INES DE CARACTERES 11.1. LES CHA

87

erreur de segmentation dans le meilleur des cas, soit une ex ecution erron ee et al eatoire du programme. Remarque : Il est important de retenir que les deux d eclarations suivantes : char v[] = "abcd" ; char *p = "abcd" ; ne sont pas equivalentes. La premi` ere d eclare un vecteur tableau de 5 caract` eres, initialis e avec les caract` eres a, b, c, d, 0 ; la seconde d eclare un pointeur de caract` ere initialis e avec ladresse de la constante cha ne de caract` eres abcd. La di erence fondamentale entre ces deux objets est que le contenu du tableau est modiable alors que celui de la cha ne ne lest pas. G en eralement, les constantes litt erales cha nes de caract` eres sont rang ees dans des blocs de m emoire prot eg es physiquement en ecriture. Toute tentative de modication provoque une erreur. Par exemple provoque une erreur lors de la tentative de modication de *p. tblvsptr.c #include <stdlib.h> #include <stdio.h> char v[] = "abcd"; char *p = "abcd"; int main(){ printf("Modification de v[0]\n"); v[0]=A; printf("OK\nModification de *p\n"); *p=A; printf("OK\n"); return EXIT_SUCCESS; }

Programme 29: Tableau vs. Pointeur (tblvsptr.c)

Remarque : Il faut egalement faire attention ` a lerreur suivante. Un identicateur de tableau lettres est utilis e dans la partie gauche dune aectation. Il illustre le fait quun identicateur de tableau est une constante et ne peut faire lobjet dune aectation. En C, un tableau nest pas une variable, mais une suite de variables. Il nest pas directement modiable au moyen dune aectation. En revanche, il est possible de modier chacun de ses el ements.

88

CHAPITRE 11. QUELQUES COMPLEMENTS

tblvsptr1.c #include <stdlib.h> #include <stdio.h> int main(){ char majuscules[] = "ABCDEFGHIJKLMNOPQRSTUVXYZ"; char lettres[26]; lettres = majuscules; return EXIT_SUCCESS; }

Programme 30: Tableau vs. Pointeur (tblvsptr1.c)

11.2

Gestion des chiers

Nous avons vu comment passer des arguments sur la ligne de commande (dans les arguments de la fonction main) ou comment prendre des valeurs tap ees au clavier pendant lex ecution du programme, avec la commande scanf. Mais parfois, les donn ees proviennent dun chier, ou des r esultats doivent etre stock es dans un chier. Cette section pr esente les rudiments de la gestion des chiers en C.

11.2.1

Type chier

Tout dabord, un chier est identi e par un objet de type FILE *, il sagit dun ux. Trois ux sont d enis par d efaut : stdin, lentr ee standard, i.e. le clavier stdout, la sortie standard, i.e. l ecran stderr, la sortie des erreurs standard, i.e. l ecran

11.2.2

Cr eation dun chier

Pour cr eer un nouveau ux, il faut lassocier ` a un chier physique, d esign e sous UNIX par une cha ne de caract` eres (le chemin relatif ou absolu). Ce lien seectue par la commande fopen :

FILE * fopen (const char * path, const char * mode)

o` u path est la cha ne de caract` eres qui d esigne lemplacement du chier dans la hi erarchie du disque, et mode d esigne le mode de louverture :

11.3. C 99

89

r (read), le chier est ouvert en lecture seule. Le curseur se positionne en t ete de chier. w (write), le chier est cr e e (ou recr e e) vide en ecriture. Le curseur se positionne en t ete de chier. a (append), le chier est ouvert en ecriture. Sil nexiste pas, il est cr e e vide. Le curseur se positionne en n de chier.

11.2.3

Lecture/Ecriture

Il est possible dutiliser fprintf et fscanf, qui fonctionnent exactement comme printf et scanf (voir chapitre 4) avec un premier argument suppl ementaire : le chier. Pour lire ou ecrire des caract` eres, il est possible dutiliser les fonctions fgetc et fputc (voir programme 31). Apr` es chaque lecture, le curseur avance dans le chier lu. Il en est de m eme pour la position d ecriture.

11.2.4

Fin de chier

` tout moment, on peut savoir si lon est arriv A e` a la n du chier avec la commande feof. Etant donn e un ux, cette commande retourne 0 si la n nest pas atteinte, et un nombre non nul dans le cas contraire.

int feof(FILE * file)

11.2.5

Cl oture

Lorsque le chier nest plus utile, on le ferme pour lib erer un ux (le nombre de ux etant limit e) :

int fclose(FILE * file)

11.3

C 99

La norme C99 repr esente une evolution importante du langage. On peut citer les changements suivants : la possibilit e de m elanger les d eclarations et les instructions, lintroduction du type bool een et complexe, diverses extensions venues enrichir les m ecanismes de d eclaration, comme les tableaux de taille variable ou les fonctions en ligne, lajout de nouveaux types entiers. Les modications les plus importantes concernent la biblioth` eque de fonctions standard dont le nombre denviron 150 dans la premi` ere version est pass e` a plus de 480.

90

CHAPITRE 11. QUELQUES COMPLEMENTS

11.4

La biblioth` eque standard

Le langage C pur se limite aux d eclarations, expressions, instructions et blocs dinstructions, structures de contr ole, et fonctions. Il ny a pas dinstructions dentr ee/sortie par exemple. Celles-ci sont impl ement ees sous la forme de fonctions contenues dans la biblioth` eque du langage C. Cette biblioth` eque, initialement con cue pour interagir avec le syst` eme UNIX etait ` a lorigine tr` es d ependante de limpl ementation, et cela a constitu e pendant plusieurs ann ees la dicult e de portage des programmes C. Ce probl` eme a et e r esolu avec, la norme ISO/IEC 9899, qui xe et d ecrit lensemble des fonctions standard du langage, et dautre part avec la norme POSIX.1 qui pr ecise linterface avec le syst` eme dexploitation. Un programme se limitant aux fonctions standard est portable dans tout lenvironnement C standard. Des erreurs peuvent subvenir dans les appels de fonctions de la biblioth` eque standard. Chaque erreur est codi ee par un num ero associ e` a un message sp ecique. Le num ero de lerreur est accessible au moyen du symbole externe errno assimilable ` a un identicateur de variable. Il re coit un code derreur lors dun d eroulement incorrect de certaines fonctions de biblioth` eque. La valeur de errno nest pas automatiquement remise ` a z ero par les fonctions de la biblioth` eque. Il est possible didentier une erreur survenue lors de lex ecution de certaines des fonctions de la biblioth` eque standard en testant la valeur de la variable globale errno. Il est dans ce cas indispensable de mettre errno ` a z ero avant deectuer lappel ` a la fonction. Voici un petit exemple achant les valeurs des erreurs. La fonction char *strerror(int numero-d-erreur) retourne le message derreur, alors que la fonction void perror(const char *en-tete) ache la concat enation de la cha ne en-tete, de la cha ne : et du message derreur.

` STANDARD 11.4. LA BIBLIOTHEQUE

91

copie.c #include <stdio.h> int TestFinDeFichier(FILE * fichier) { return (feof(fichier));} void EcritCaractere(FILE * out, char val) { fputc(val,out);} char LitCaractere(FILE * in) { return (fgetc(in));} int main (int argc, char *argv[]) { FILE *in,*out; char fichierin[80], fichierout[80]; char c; if (argc!=3) { printf("Usage: copie <in> <out> \n"); exit(0);} strcpy(fichierin,argv[1]); strcpy(fichierout,argv[2]); in=fopen(fichierin,"r"); if (!in) { printf("Fichier %s inexistant \n",fichierin); exit(0);} out=fopen(fichierout,"w"); if (!out) { printf("Probl` eme de cr eation du fichier %s \n",fichierout); exit(0);} c=LitCaractere(in); while(!TestFinDeFichier(in)) { EcritCaractere(out,c); c=LitCaractere(in);} fclose(in); fclose(out); return(0); }

Programme 31: Gestion des chiers (copie.c)

92

CHAPITRE 11. QUELQUES COMPLEMENTS

perror.c #include #include #include #include #include #include <stdlib.h> <string.h> <stdio.h> <errno.h> <locale.h> <math.h>

#define PERROR(appel) errno = 0; appel; print_error("- " #appel) static void print_error(char *source) { int e = errno; perror(source); printf("errno: %d -- %s\n\n", e, strerror(e)); } int main() { PERROR(acos(2.0)); PERROR(fopen("/", "w")); PERROR(fopen("?", "r")); PERROR(strtol("1234567890", 0, 0)); PERROR(strtol("12345678900", 0, 0)); PERROR(malloc(100000000000)); PERROR(malloc(1000000000000)); return EXIT_SUCCESS; }

Programme 32: Erreurs dans la biblioth` eque standard (perror.c)