Top Banner
8/14/2019 cour de C http://slidepdf.com/reader/full/cour-de-c 1/238 Mar 16, 2009 F.KHOUKHI 1 Module Algorithmique & langage C F. KHOUKHI 2006
238

cour de C

May 30, 2018

Download

Documents

Ihsan Mokhlisse
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 1/238

Mar 16, 2009 F.KHOUKHI 1

ModuleAlgorithmique & langage C

F. KHOUKHI2006

Page 2: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 2/238

Mar 16, 2009 F.KHOUKHI 2

P L A N

• Chapitre 1 : les bases de la programmation en C

• Chapitre 2 : les types composés

• Chapitre 3 : les pointeurs

• Chapitre 4 : les fonctions

• Chapitre 5 : Les directives au préprocesseur 

• Chapitre 6 : La gestion des fichiers

• Chapitre 7 : La programmation modulaire

Page 3: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 3/238

Mar 16, 2009 F.KHOUKHI 3

Chapitre 1

• les bases de la programmation en C

Page 4: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 4/238

Mar 16, 2009 F.KHOUKHI 4

1.1 Historique

• Le C a été conçu en 1972 par Dennis Richieet Ken Thompson, chercheurs aux Bell Labs,afin de développer un système d'exploitationUNIX sur un DEC PDP-11.

• Le C devenant de plus en plus populairedans les années 80. En 1983, l'ANSI(American National Standards Institute)décida de normaliser le langage ; ce travails'acheva en 1989 par la définition de lanorme ANSI C. Celle-ci fut reprise telle quellepar l'ISO (International StandardsOrganization) en 1990.

Page 5: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 5/238

Mar 16, 2009 F.KHOUKHI 5

 1.2 La compilation

Le C est un langage compilé (par opposition aux langagesinterprétés). Cela signifie qu'un programme C est décrit par un fichier texte, appelé fichier source.

Ce fichier n'étant évidemment pas exécutable par lemicroprocesseur, il faut le traduire en langage machine.

Cette opération est effectuée par un programme appelécompilateur.

La compilation se décompose en fait en 4 phasessuccessives :

Page 6: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 6/238

Mar 16, 2009 F.KHOUKHI 6

 1.2 La compilation

1. Le traitement par le préprocesseur : le fichier source estanalysé par le préprocesseur qui effectue destransformations purement textuelles (remplacement dechaînes de caractères, inclusion d'autres fichiers source...).

2. La compilation : la compilation proprement dite traduit lefichier généré par le préprocesseur en assembleur, c'est-à-

dire en une suite d'instructions du microprocesseur quiutilisent des mnémoniques rendant la lecture possible.

Page 7: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 7/238

Mar 16, 2009 F.KHOUKHI 7

 1.2 La compilation

3. L'assemblage: cette opération transforme le code

assembleur en un fichier binaire, c'est-à-dire en instructionsdirectement compréhensibles par le processeur.Généralement, la compilation et l'assemblage se font dans lafoulée, sauf si l'on spécifie explicitement que l'on veut le

code assembleur. Le fichier produit par l'assemblage estappelé fichier objet.

4. L'édition de liens : un programme est souvent séparé enplusieurs fichiers source, pour des raisons de clarté mais

aussi parce qu'il fait généralement appel à des librairies defonctions standard déjà écrites. Une fois chaque code sourceassemblé, il faut donc lier entre eux les différents fichiersobjets. L'édition de liens produit alors un fichier ditexécutable.

Page 8: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 8/238

Mar 16, 2009 F.KHOUKHI 8

1.3 Les composants élémentaires du C

Un programme en langage C est constitué des sixgroupes de composants élémentaires suivants :

les identificateurs,les mots-clefs,

les constantes,les chaînes de caractères,les opérateurs,les signes de ponctuation.

On peut ajouter à ces six groupes les commentaires,qui sont enlevés par le préprocesseur.

Page 9: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 9/238

Mar 16, 2009 F.KHOUKHI 9

1.3.1 Les identificateurs

Le rôle d'un identificateur est de donner un nom à uneentité du programme. Plus précisément, unidentificateur peut désigner :

un nom de variable ou de fonction,

un type défini par typedef, struct, union ou enum,une étiquette.

Un identificateur est une suite de caractères parmi :

•  les lettres (minuscules ou majuscules, mais non accentuées),• les chiffres,• le ``blanc souligné'' (_).

Page 10: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 10/238

Mar 16, 2009 F.KHOUKHI 10

 1.3.2 Les mots-clefs

Un certain nombre de mots, appelés mots-clefs, sontréservés pour le langage lui-même et ne peuvent pas êtreutilisés comme identificateurs. L'ANSI C compte 32 motsclefs :auto const double float int short struct unsigned

break continue else for long signed switch voidcase default enum goto register sizeof typedef volatilechar do extern if return static union while

que l'on peut ranger en catégories :

Page 11: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 11/238

Mar 16, 2009 F.KHOUKHI 11

 1.3.2 Les mots-clefs et ses catégories

les spécificateurs de stockage : auto register staticextern typedef 

L es spécificateurs de type: char double enum floatint long short signed struct union unsigned void

Les qualificateurs de type: const volatile

les instructions de contrôle: break case continue

default do else for goto if switch while

divers: return sizeof 

Page 12: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 12/238

Mar 16, 2009 F.KHOUKHI 12

1.3.3 Les commentaires

• Un commentaire débute par /* et se terminepar */.

• Par exemple,

• /* Ceci est un commentaire */

• On ne peut pas imbriquer descommentaires. Quand on met en

commentaire un morceau de programme, ilfaut donc veiller à ce que celui-ci necontienne pas de commentaire.

Page 13: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 13/238

Mar 16, 2009 F.KHOUKHI 13

1.4 Structure d'un programme C

• Une expression est une suite de composantsélémentaires syntaxiquement correcte,

Exemple

x = 0

ou bien

(i >= 0) && (i < 10) && (p[i] != 0)

Page 14: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 14/238

Mar 16, 2009 F.KHOUKHI 14

1.4 Structure d'un programme C

• Une instruction est une expression suivie d'un point-virgule. Le point-virgule signifie en quelque sorte``évaluer cette expression''. Plusieurs instructionspeuvent être rassemblées par des accolades { et } pour 

former une instruction composée ou bloc qui estsyntaxiquement équivalent à une instruction.• Exemple: if (x != 0) { z = y / x; t = y % x; }• Une instruction composée d'un spécificateur de type et

d'une liste d'identificateurs séparés par une virgule estune déclaration.

• Exemple: int a; int b = 1, c; double x = 2.38e4;• char message[80];

Page 15: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 15/238

Mar 16, 2009 F.KHOUKHI 15

1.4 Structure d'un programme C

Un programme C se présente de la façon suivante :[directives au préprocesseur][déclarations de variables externes][fonctions secondaires]

main(){déclarations de variables internesinstructions

}

Page 16: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 16/238

Mar 16, 2009 F.KHOUKHI 16

1.4 Structure d'un programme C

La fonction principale main peut avoir des paramètresformels. On supposera dans un premier temps que lafonction main n'a pas de valeur de retour. Ceci est tolérépar le compilateur mais produit un message

d'avertissement quand on utilise l'option -Wall de gcc (cf.chapitre 4).

Page 17: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 17/238

Mar 16, 2009 F.KHOUKHI 17

1.4 Structure d'un programme C

Les fonctions secondaires peuvent être placéesindifféremment avant ou après la fonction principale. Unefonction secondaire peut se décrire de la manière suivante :type ma_fonction ( arguments )

{déclarations de variables internesinstructions

}Cette fonction retournera un objet dont le type sera type (à

l'aide d'une instruction comme return objet;). Les argumentsde la fonction obéissent à une syntaxe voisine de celle desdéclarations : on met en argument de la fonction une suited'expressions type objet séparées par des virgules.

Page 18: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 18/238

Mar 16, 2009 F.KHOUKHI 18

1.4 Structure d'un programme C

Par exemple, la fonction secondaire suivante calcule leproduit de deux entiers :int produit(int a, int b){

int resultat; 

resultat = a * b;return(resultat);

}

Page 19: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 19/238

Mar 16, 2009 F.KHOUKHI 19

1.5 Les types prédéfinis

Le C est un langage typé. Cela signifie en particulier quetoute variable, constante ou fonction est d'un type précis. Letype d'un objet définit la façon dont il est représenté enmémoire•  La taille mémoire correspondant aux différents typesdépend des compilateurs ; toutefois, la norme ANSIspécifie un certain nombre de contraintes.

• Les types de base en C concernent les caractères, lesentiers et les flottants (nombres réels). Ils sont désignéspar les mots-clefs suivants :

• char , int , float, double ,short, long unsigned

Page 20: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 20/238

Mar 16, 2009 F.KHOUKHI 20

1.5.1 Le type caractère 

Le mot-clef char désigne un objet de type caractère. Un char peut contenir n'importe quel élément du jeu de caractères dela machine utilisée. La plupart du temps, un objet de type char est codé sur un octet ; c'est l'objet le plus élémentaire en C.

Le jeu de caractères utilisé correspond généralement aucodage ASCII (sur 7 bits). La plupart des machines utilisentdésormais le jeu de caractères ISO-8859 (sur 8 bits), dont les128 premiers caractères correspondent aux caractères ASCII.

Les 128 derniers caractères (codés sur 8 bits) sont utiliséspour les caractères propres aux différentes langues

Page 21: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 21/238

Mar 16, 2009 F.KHOUKHI 21

1.5.1 Le type caractère Une des particularités du type char en C est qu'il peut êtreassimilé à un entier : tout objet de type char peut être utilisédans une expression qui utilise des objets de type entier. Par exemple, si c est de type char, l'expression c + 1 est valide.Elle désigne le caractère suivant dans le code ASCII.main()

{char c = 'A';printf("%c", c + 1);

}

Suivant les implémentations, le type char est signé ou non. Encas de doute, il vaut mieux préciser unsigned char ou signedchar. Notons que tous les caractères imprimables sontpositifs.

Page 22: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 22/238

Mar 16, 2009 F.KHOUKHI 22

 1.5.2 Les types entiers

Le mot-clef désignant le type entier est int. Un objet detype int est représenté par un mot ``naturel'' de lamachine utilisée, 32 bits pour un DEC alpha ou un PC

Intel.

•Le type int peut être précédé d'un attribut de précision(short ou long) et/ou d'un attribut de représentation(unsigned).Un objet de type short int a au moins la tailled'un char et au plus la taille d'un int. En général, unshort int est codé sur 16 bits. Un objet de type long inta au moins la taille d'un int (64 bits sur un DEC alpha,32 bits sur un PC Intel).

Page 23: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 23/238

Mar 16, 2009 F.KHOUKHI 23

1.5.2 Les types entiers

entier 32 bits64 bitsLong

Entier 32 bits32 bitsInt

entier court16 bits16 bitsShort

caractère8 bits8 bitsChar 

PC

Intel

DEC

Alpha

Page 24: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 24/238

Mar 16, 2009 F.KHOUKHI 24

1.5.2 Les types entiersLe bit de poids fort d'un entier est son signe. Un entier positif estdonc représenté en mémoire par la suite de 32 bits dont le bit de

poids fort vaut 0 et les 31 autres bits correspondent à ladécomposition de l'entier en base 2. Par exemple, pour des objetsde type char (8 bits), l'entier positif 12 sera représenté en mémoirepar 00001100. Un entier négatif est, lui, représenté par une suite de32 bits dont le bit de poids fort vaut 1 et les 31 autres bits

correspondent à la valeur absolue de l'entier représentée suivantla technique dite du ``complément à 2''. Ainsi, pour des objets detype signed char (8 bits), -1 sera représenté par 11111111, -2 par 11111110, -12 par par 11110100.Un int peut donc représenter unentier entre -231 et (231 -1). L'attribut unsigned spécifie que l'entier 

n'a pas de signe. Un unsigned int peut donc représenter un entier entre 0 et (232-1). Sur un DEC alpha, on utilisera donc un des typessuivants en fonction de la taille des données à stocker 

Page 25: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 25/238

Mar 16, 2009 F.KHOUKHI 25

1.5.2 Les types entiers

• signed char[-27;27[

• unsigned char[0;28[• short int[-215; 215[• unsigned short int[0;216[• int[-231;231[

• unsigned int[0;232

[• long int (DEC alpha)[-263;263[• unsigned long int (DEC alpha)[0;264[

• Plus généralement, les valeurs maximales et minimalesdes différents types entiers sont définies dans la librairiestandard limits.h.

Page 26: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 26/238

Mar 16, 2009 F.KHOUKHI 26

1.5.2 Les types flottants• Les types float, double et long double servent à représenter des

nombres en virgule flottante. Ils correspondent aux différentes

précisions possibles.

Flottant Quadruple précision128 bits64 bitsLong doubleFlottant double précision64 bits64 bitsdouble

flottant32 bits32 bitsfloat

PC

Intel

DEC

Alpha

Les flottants sont généralement stockés en mémoire sous lareprésentation de la virgule flottante normalisée. On écrit le nombre sousla forme ``signe 0,mantisse  B exposant ''. En général, B=2. Le digit de poidsfort de la mantisse n'est jamais nul.Un flottant est donc représenté par une suite de bits dont le bit de poidsfort correspond au signe du nombre. Le champ du milieu correspond à lareprésentation binaire de l'exposant alors que les bits de poids faibleservent à représenter la mantisse.

Page 27: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 27/238

Mar 16, 2009 F.KHOUKHI 27

1.6 Les constantes

• Une constante est une valeur qui apparaît littéralementdans le code source d'un programme, le type de laconstante étant déterminé par la façon dont la constante

est écrite. Les constantes peuvent être de 4 types :entier, flottant (nombre réel), caractère, énumération.Ces constantes vont être utilisées, par exemple, pour initialiser une variable.

Page 28: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 28/238

Mar 16, 2009 F.KHOUKHI 28

1.6.1 Les constantes entières

• Une constante entière peut être représentée de 3 manièresdifférentes suivant la base dans laquelle elle est écrite :

• décimale : par exemple, 0 et 2437348 sont des constantes entièresdécimales.

• octale : la représentation octale d'un entier correspond à sadécomposition en base 8. Les constantes octales doiventcommencer par un zéro. Par exemple, les représentations octalesdes entiers 0 et 255 sont respectivement 00 et 0377.

• hexadécimale : la représentation hexadécimale d'un entier correspond à sa décomposition en base 16. Les lettres de a à f sont

utilisées pour représenter les nombres de 10 à 15. Les constanteshexadécimales doivent commencer par 0x ou 0X. Par exemple, lesreprésentations hexadécimales de 14 et 255 sont respectivement0xe et 0xff.

Page 29: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 29/238

Mar 16, 2009 F.KHOUKHI 29

1.6.1 Les constantes entières

• Par défaut, une constante décimale est représentéeavec le format interne le plus court permettant de lareprésenter parmi les formats des types int, long intet unsigned long int

• tandis qu'une constante octale ou hexadécimale estreprésentée avec le format interne le plus courtpermettant encore de la représenter parmi lesformats des types int, unsigned int, long int etunsigned long int.

Page 30: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 30/238

Mar 16, 2009 F.KHOUKHI 30

1.6.1 Les constantes entières

•  On peut cependant spécifier explicitement leformat d'une constante entière en la suffixant par uou U pour indiquer qu'elle est non signée, ou en lasuffixant par l ou L pour indiquer qu'elle est de type

long.

constante type1234 int02322 int /* octal */

0x4D2 int /* hexadécimal */123456789L long1234U unsigned int123456789UL unsigned long int

Page 31: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 31/238

Mar 16, 2009 F.KHOUKHI 31

1.6.2 Les constantes réelles

•  Les constantes réelles sont représentées par lanotation classique par mantisse et exposant.L'exposant est introduit par la lettre e ou E ; il s'agitd'un nombre décimal éventuellement signé.

constante type12.34 double12.3e-4 double

12.34F float12.34L long double

Page 32: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 32/238

Mar 16, 2009 F.KHOUKHI 32

1.6.3 Les constantes caractères

• Pour désigner un caractère imprimable, il suffit dele mettre entre apostrophes (par ex. 'A' ou '$'). Lesseuls caractères imprimables qu'on ne peut pasreprésenter de cette façon sont l'antislash et

l'apostrophe, qui sont respectivement désignés par   \\ et \'. Le point d'interrogation et les guillemetspeuvent aussi être désignés par les notations \? et  \". Les caractères non imprimables peuvent être

désignés par '\code-octal' où code-octal est le codeen octal du caractère.

Page 33: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 33/238

Mar 16, 2009 F.KHOUKHI 33

1.6.3 Les constantes caractères

• Toutefois, les caractères non-imprimables les plusfréquents disposent aussi d'une notation plussimple :

•  \n nouvelle ligne \r retour chariot•  \t tabulation horizontale \f saut de page

•  \v tabulation verticale \a signal d'alerte

•  \b retour arrière

Page 34: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 34/238

Mar 16, 2009 F.KHOUKHI 34

1.6.4 Les constantes chaines de caratères

•  Une chaîne de caractères est une suite decaractères entourés par des guillemets. Par exemple:

•"Ceci est une chaîne de caractères"

1 7 Les opérateurs

Page 35: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 35/238

Mar 16, 2009 F.KHOUKHI 35

1.7 Les opérateurs

• L'affectation

• Les opérateurs arithmétiques• Les opérateurs relationnels

• Les opérateurs logiques booléens

• Les opérateurs logiques bit à bit

• Les opérateurs d'affectation composée

• Les opérateurs d'incrémentation et de décrémentation

• L'opérateur virgule

• L'opérateur conditionnel ternaire• L'opérateur de conversion de type

• L'opérateur adresse

1 7 1 L'affectation

Page 36: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 36/238

Mar 16, 2009 F.KHOUKHI 36

1.7.1 L affectation Elle est symbolisée par le signe =

variable = expression Le terme de gauche de l'affectation peut être unevariable simple, un élément de tableau mais pas uneconstante. Cette expression a pour effet d'évaluer 

expression et d'affecter la valeur obtenue à variable. Deplus, cette expression possède une valeur, qui est celleexpression. Ainsi, l'expression i = 5 vaut 5

main()

{ int i, j = 2; float x = 2.5; i = j + x; x = x + i; printf("\n %f \n",x);}

 imprime pour x la valeur 6.5 (et non 7), car dans l'instruction i = j + x;

l'expression j + x a été convertie en entier.

1 7 2 Les opérateurs arithmétiques

Page 37: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 37/238

Mar 16, 2009 F.KHOUKHI 37

1.7.2 Les opérateurs arithmétiques

Les opérateurs arithmétiques classiques sont l'opérateur unaire - (changement de signe) ainsi que les opérateurs

binaires:

+ addition

- soustraction

* multiplication

 / division

% reste de la division (modulo)

1 7 2 Les opérateurs arithmétiques

Page 38: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 38/238

Mar 16, 2009 F.KHOUKHI 38

1.7.2 Les opérateurs arithmétiques

Contrairement à d'autres langages, le C ne dispose que de lanotation / pour désigner à la fois la division entière et la

division entre flottants. Si les deux opérandes sont de typeentier, l'opérateur / produira une division entière (quotient dela division). Par contre, il délivrera une valeur flottante dès quel'un des opérandes est un flottant.

Exemple: float x= 3 / 2; affecte à x la valeur 1.5 par contre intx=3/2 affecte à x la valeur 1

L'opérateur % ne s'applique qu'à des opérandes de typeentier. Si l'un des deux opérandes est négatif, le signe dureste dépend de l'implémentation, mais il est en général le

même que celui du dividendeNotons enfin qu'il n'y a pas en C d'opérateur effectuantl'élévation à la puissance. De façon générale, il faut utiliser lafonction pow(x,y) de la librairie math.h pour calculer   x y .

1 7 3 Les opérateurs relationnels

Page 39: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 39/238

Mar 16, 2009 F.KHOUKHI 39

1.7.3 Les opérateurs relationnels

Contrairement à d'autres langages, le C ne dispose que de la >strictement supérieur 

>= supérieur ou égal

< strictement inférieur 

<= inférieur ou égal

== égal

!= différent

Leur syntaxe est expression-1 op expression-2

Les deux expressions sont évaluées puis comparées. La

valeur rendue est de type int (il n'y a pas de type booléen enC); elle vaut 1 si la condition est vraie, et 0 sinon.

1 7 3 Les opérateurs relationnels

Page 40: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 40/238

Mar 16, 2009 F.KHOUKHI 40

1.7.3 Les opérateurs relationnels

Attention à ne pas confondre l'opérateur de test d'égalité ==avec l'opérateur d'affection =. Ainsi, le programme

main()

{

int a = 0;

int b = 1;

if (a = b)

printf("\n a et b sont egaux \n");

else

printf("\n a et b sont differents \n");

}

imprime à l'écran a et b sont egaux !

1 7 4 Les opérateurs logiques booléens

Page 41: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 41/238

Mar 16, 2009 F.KHOUKHI 41

1.7.4 Les opérateurs logiques booléens

&& et logique

|| ou logique! négation logique

Comme pour les opérateurs de comparaison, la valeur retournée par ces opérateurs est un int qui vaut 1 si lacondition est vraie et 0 sinon.

Dans une expression de type

expression-1 op-1 expression-2 op-2 ...expression-n

l'évaluation se fait de gauche à droite et s'arrête dès que le

résultat final est déterminé. Par exemple dansint i;int p[10]; if ((i >= 0) && (i <= 9) && !(p[i] == 0))

la dernière clause ne sera pas évaluée si i n'est pas entre 0 et9.

Page 42: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 42/238

Mar 16, 2009 F.KHOUKHI 42

1.7.5 Les opérateurs logiques bit à bit

101

000

10&

111

100

10|

Les six opérateurs suivants permettent de manipuler desentiers au niveau du bit. Ils s'appliquent aux entiers de toute

longueur (short, int ou long), signés ou non

& et | ou inclusif 

^ ou exclusif ~ complément à 1

<< décalage à gauche >> décalage à droite

En pratique, les opérateurs &, | et ~ consistent à appliquer bità bit les opérations suivantes

011

100

10^

Page 43: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 43/238

Mar 16, 2009 F.KHOUKHI 43

1.7.5 Les opérateurs logiques bit à bit

L'opérateur unaire ~ change la valeur de chaque bit d'unentier. Le décalage à droite et à gauche effectuentrespectivement une multiplication et une division par unepuissance de 2. Notons que ces décalages ne sont pas desdécalages circulaires (ce qui dépasse disparaît).

Page 44: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 44/238

Mar 16, 2009 F.KHOUKHI 44

1.7.5 Les opérateurs logiques bit à bit

division entière par 21100001011b >> 1

ce qui dépasse disparaît11211100000b << 5

multiplication par 49201011100b << 217810110010~a

9001011010a ^ b

9501011111a | b

500000101a & b

2300010111b

7701001101a

décimalebinaireexpression

Considérons par exemple les entiers a=77 et b=23 de

type unsigned char (i.e. 8 bits). En base 2 il s'écriventrespectivement 01001101 et 00010111.

Page 45: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 45/238

Mar 16, 2009 F.KHOUKHI 45

1.7.6 Les opérateurs d'affectation composée

division entière par 21100001011b >> 1

ce qui dépasse disparaît11211100000b << 5

multiplication par 49201011100b << 217810110010~a

9001011010a ^ b

9501011111a | b

500000101a & b

2300010111b

7701001101a

décimalebinaireexpression

Les opérateurs d'affectation composée sont :

+= -= *= /= %= &= ^= |= <<= >>=

Page 46: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 46/238

Mar 16, 2009 F.KHOUKHI 46

1.7.7 Les opérateurs d'incrémentation et dedécrémentation

Les opérateurs d'incrémentation ++ et de

décrémentation -- s'utilisent aussi bien en suffixe (i++)qu'en préfixe (++i). Dans les deux cas la variable i seraincrémentée, toutefois dans la notation suffixe lavaleur retournée sera l'ancienne valeur de i alors que

dans la notation préfixe se sera la nouvelle.

int a = 3, b, c; b = ++a; /* a et b valent 4 */ c = b++; /* c vaut 4 et b vaut 5 */

Page 47: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 47/238

Mar 16, 2009 F.KHOUKHI 47

1.7.8 L'opérateur virguleUne expression peut être constituée d'une suite

d'expressions séparées par des virgules :

expression-1, expression-2, ... , expression-n

main()

{int a, b;

b = ((a = 3), (a + 2));

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

}imprime b = 5.

Page 48: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 48/238

Mar 16, 2009 F.KHOUKHI 48

1.7.9 L'opérateur conditionnel ternaire

L'opérateur conditionnel ? est un opérateur ternaire.

Sa syntaxe est la suivante :

condition ? expression-1 : expression-2

Cette expression est égale à expression-1 si condition est satisfaite, et àexpression-2 sinon. Par exemple, l'expression

x >= 0 ? x : -xcorrespond à la valeur absolue d'un nombre

 m = ((a > b) ? a : b); affecte à m le maximum de a et de b

Page 49: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 49/238

Mar 16, 2009 F.KHOUKHI 49

1.7.10 L'opérateur de conversion de type

L'opérateur de conversion de type, appelé cast, permet

de modifier explicitement le type d'un objet. On écrit :

(type) objet

Par exemple,

main(){

int i = 3, j = 2;

printf("%f \n",(float)i/j);

}retourne la valeur 1.5.

Page 50: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 50/238

Mar 16, 2009 F.KHOUKHI 50

1.7.11 L'opérateur adresse

L'opérateur d'adresse & appliqué à une variable

retourne l'adresse-mémoire de cette variable. Lasyntaxe est & objet

Page 51: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 51/238

Mar 16, 2009 F.KHOUKHI 51

1.7.12 Règles de priorité des opérateurs

Le tableau suivant classe les opérateurs par ordres de

priorité décroissants. Les opérateurs placés sur unemême ligne ont même priorité. Si dans une expressionfigurent plusieurs opérateurs de même priorité, l'ordred'évaluation est définie par la flèche de la seconde

colonne du tableau. On préferera toutefois mettre desparenthèses en cas de doute...

1 7 12 Rè l d i ité d é t

Page 52: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 52/238

Mar 16, 2009 F.KHOUKHI 52

1.7.12 Règles de priorité des opérateurs

,

= += -= *= /= %= &= ^= |= <<= >>=

? :

||&&

|

^

&(et bit-à-bit)

== !=< <= > >=

<< >>

+ -(binaire)

* / %

! ~ ++ -- -(unaire) (type) *(indirection) &(adresse) sizeof 

() [] -> .

 opérateurs

1 7 12 Rè l d i ité d é t

Page 53: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 53/238

Mar 16, 2009 F.KHOUKHI 53

1.7.12 Règles de priorité des opérateurs

Par exemple, les opérateurs logiques bit-à-bit sontmoins prioritaires que les opérateurs relationnels. Cela

implique que dans des tests sur les bits, il fautparenthéser les expressions.

Par exemple, il faut écrire if ((x ^ y) != 0)

1 8 L i t ti d b h t

Page 54: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 54/238

Mar 16, 2009 F.KHOUKHI 54

1.8 Les instructions de branchementconditionnel

On appelle instruction de contrôle toute instruction quipermet de contrôler le fonctionnement d'un

programme. Parmi les instructions de contrôle, ondistingue les instructions de branchement et lesboucles. Les instructions de branchement permettentde déterminer quelles instructions seront exécutées etdans quel ordre

Page 55: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 55/238

Mar 16, 2009 F.KHOUKHI 55

1.8.1 Branchement conditionnel if---elseLa forme la plus générale est celle-ci :

f (expression-1 ) instruction-1

else if (expression-2 ) instruction-2

...

else if (expression-n )

instruction-n

else instruction

avec un nombre quelconque de else if ( ... ). Le dernier else est toujours facultatif. La forme la plus simple est

if (expression ) instruction

Page 56: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 56/238

Mar 16, 2009 F.KHOUKHI 56

1.8.2 Branchement multiple switchSa forme la plus générale est celle-ci :

switch (expression ){case constante-1: liste d'instructions 1 ; break;

case constante-2: liste d'instructions 2 ;break;

...

case constante-n: liste d'instructions n; break;

default: liste d'instructions ;break;

}

  la valeur de expression est égale à l'une des constantes, la listed'instructions correspondant est exécutée. Sinon la listed'instructions correspondant à default est exécutée. L'instruction

default est facultative. 

Page 57: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 57/238

Mar 16, 2009 F.KHOUKHI 57

1.9 Les bouclesLes boucles permettent de répéter une séried'instructions tant qu'une certaine condition n'est pasvérifiée.

• Boucle while

•Boucle do---while

•Boucle for 

Page 58: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 58/238

Mar 16, 2009 F.KHOUKHI 58

1.9 Les bouclesLa syntaxe de while est la suivante :

while (expression )

instruction

Tant que expression est vérifiée (i.e., non nulle),

instruction est exécutée. Si expression est nulle audépart, instruction ne sera jamais exécutée. instructionpeut évidemment être une instruction composée.

i = 1;

while (i < 10){ printf("\n i = %d",i); i++;}

le programme suivant imprime les entiers de 1 à 9

1.9.2 Boucle do---while

Page 59: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 59/238

Mar 16, 2009 F.KHOUKHI 59

Il peut arriver que l'on ne veuille effectuer le test decontinuation qu'après avoir exécuté l'instruction. Dansce cas, on utilise la boucle do---while. Sa syntaxe est:

Do instruction

while (expression );

Ici, instruction sera exécutée tant que expression est non nulle.Cela signifie donc que instruction est toujours exécutée au moinsune fois. Par exemple, pour saisir au clavier un entier entre 1 et 10int a;

do { printf("\n Entrez un entier entre 1 et 10 : ");scanf("%d",&a);

} while ((a <= 0) || (a > 10));

1.9.3 Boucle for 

Page 60: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 60/238

Mar 16, 2009 F.KHOUKHI 60

La syntaxe de for est :

for (expr 1 ;expr 2 ;expr 3) instruction

Exemple:

for (i = 0; i < 10; i++)

printf("\n i = %d",i);

Cette boucle imprimer tous les entiers de 0 à 9

int n, i, fact; for (i = 1, fact = 1; i <= n; i++)

fact *= i; printf("%d ! = %d \n",n,fact); On peut également insérer l'instruction fact *= i; dans la boucle for cequi donne : int n, i, fact;for (i = 1, fact = 1; i <= n; fact *= i, i++);

printf("%d ! = %d \n",n,fact);

Les instructions de branchement non conditionnel

Page 61: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 61/238

Mar 16, 2009 F.KHOUKHI 61

1.10.1 Branchement non conditionnel break

L'instruction break peut, plus généralement, êtreemployée à l'intérieur de n'importe quelle boucle. Ellepermet d'interrompre le déroulement de la boucle, etpasse à la première instruction qui suit la boucle. En

cas de boucles imbriquées, break fait sortir de laboucle la plus interne:

main()

{ int i;

for (i = 0; i < 5; i++)

{ printf("i = %d\n",i); if (i == 3) break; }

printf("valeur de i a la sortie de la boucle = %d\n",i);

}

i = 0

i = 1

i = 2i = 3

valeur de i a la sortie dela boucle = 3

Les instructions de branchement non conditionnel

Page 62: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 62/238

Mar 16, 2009 F.KHOUKHI 62

1.10.1 Branchement non conditionnel continue

L'instruction continue permet de passer directementau tour de boucle suivant, sans exécuter les autresinstructions de la boucle. Ainsi le programme

 main()

{int i;

for (i = 0; i < 5; i++)

{ if (i == 3) continue;

printf("i = %d\n",i);

}printf("valeur de i a la sortie de la boucle = %d\n",i);

}

i = 0

i = 1

i = 2i = 4

 valeur de i a la

sortie de la boucle

= 5 

Les instructions de branchement non conditionnel

Page 63: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 63/238

Mar 16, 2009 F.KHOUKHI 63

1.10.3 Branchement non conditionnel goto

L'instruction goto permet d'effectuer un saut jusqu'àl'instruction etiquette correspondant.

Cette instruction est déconseillée

1.11 Les fonctions d'entrées-sorties classiques

Page 64: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 64/238

Mar 16, 2009 F.KHOUKHI 64

1.11 Les fonctions d entrées sorties classiques

Il s'agit des fonctions de la librairie standard stdio.hutilisées avec les unités classiques d'entrées-sorties,qui sont respectivement le clavier et l'écran. Sur certains compilateurs, l'appel à la librairie stdio.h par ladirective au préprocesseur :#include <stdio.h>

n'est pas nécessaire pour utiliser printf et scanf 

1.11.1 La fonction d'écriture printf

Page 65: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 65/238

Mar 16, 2009 F.KHOUKHI 65

1.11.1 La fonction d écriture printf 

La fonction printf est une fonction d'impression formatée, ce quisignifie que les données sont converties selon le format

particulier choisi. Sa syntaxe est

printf("chaîne de contrôle ",expression-1, ..., expression-n);

La chaîne de contrôle contient le texte à afficher et lesspécifications de format correspondant à chaque expression de la

liste. Les spécifications de format ont pour but d'annoncer leformat des données à visualiser. Elles sont introduites par lecaractère %, suivi d'un caractère désignant le formatd'impression.

largeur minimale du champ d'impression : %10d spécifie qu'au moins 10caractères seront réservés pour imprimer l'entier.

 précision : %.12f signifie qu'un flottant sera imprimé avec 12 chiffres après la virgule. Demême %10.2f signifie que l'on réserve 12 caractères (incluant le caractère .) pour imprimer le flottant et que 2 d'entre eux sont destinés aux chiffres après la virgule.Lorsque la précision n'est pas spécifiée, elle correspond par défaut à 6 chiffres après lavirgule

1.11.1 La fonction d'écriture printf

Page 66: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 66/238

Mar 16, 2009 F.KHOUKHI 66

1.11.1 La fonction d écriture printf 

Pour une chaîne de caractères, la précision correspond au nombre de caractèresimprimés : %30.4s signifie que l'on réserve un champ de 30 caractères pour imprimer lachaîne mais que seulement les 4 premiers caractères seront imprimés (suivis de

26 blancs)

chaîne de caractèreschar*%s

caractèreunsigned char %c

décimale, représentation la plus courte parmi %lf et %lelong double%lg

décimale, représentation la plus courte parmi %f et %edouble%g

décimale notation exponentiellelong double%le

décimale notation exponentielledouble%e

décimale virgule fixelong double%lf 

décimale virgule fixedouble%f 

hexadécimale non signéeunsigned long int%lx

hexadécimale non signéeunsigned int%x

octale non signéeunsigned long int%lo

octale non signéeunsigned int%o

décimale non signéeunsigned long int%lu

décimale non signéeunsigned int%u

décimale signéelong int%ld

décimale signéeint%d

écritureconversion enformat

1.11.1 La fonction d'écriture printf 

Page 67: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 67/238

Mar 16, 2009 F.KHOUKHI 67

p

#include <stdio.h>

main() { int i = 23674; int j = -23674; long int k = (1l << 32);double x = 1e-8 + 1000; char c = 'A'; char *chaine = "chaine de caracteres";printf("impression de i: \n"); printf("%d \t %u \t %o \t %x",i,i,i,i);printf("\nimpression de j: \n"); printf("%d \t %u \t %o \t %x",j,j,j,j);printf("\nimpression de k: \n"); printf("%d \t %o \t %x",k,k,k);

printf("\n%ld \t %lu \t %lo \t %lx",k,k,k,k); printf("\nimpression de x: \n");

printf("%f \t %e \t %g",x,x,x);

printf("\n%.2f \t %.2e",x,x); printf("\n%.20f \t %.20e",x,x);

printf("\nimpression de c: \n"); printf("%c \t %d",c,c);printf("\nimpression de chaine: \n"); printf("%s \t %.10s",chaine,chaine);printf("\n"); }

1.11.1 La fonction d'écriture printf 

Page 68: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 68/238

Mar 16, 2009 F.KHOUKHI 68

pCe programme imprime à l'écran :

impression de i:

23674 23674 56172 5c7a

impression de j:

-23674 4294943622 37777721606 ffffa386

impression de k:

0 0 0

4294967296 4294967296 40000000000 100000000impression de x:

1000.000000 1.000000e+03 1000

1000.00 1.00e+03

1000.00000001000000000000 1.00000000001000000000e+03

impression de c:

A 65

impression de chaine:

chaine de caracteres chaine de

1.11.2 La fonction de saisie scanf 

Page 69: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 69/238

Mar 16, 2009 F.KHOUKHI 69

La fonction scanf permet de saisir des données au clavier et de lesstocker aux adresses spécifiées par les arguments de la fonctions.

scanf("chaîne de contrôle",argument-1,...,argument-n)La chaîne de contrôle indique le format dans lequel les donnéeslues sont converties. Elle ne contient pas d'autres caractères(notamment pas de \n). Comme pour printf, les conversions deformat sont spécifiées par un caractère précédé du signe %. Les

formats valides pour la fonction scanf diffèrent légèrement de ceuxde la fonction printf.

Les données à entrer au clavier doivent être séparées par desblancs ou des <RETURN> sauf s'il s'agit de caractères. On peuttoutefois fixer le nombre de caractères de la donnée à lire. Par 

exemple %3s pour une chaîne de 3 caractères, %10d pour unentier qui s'étend sur 10 chiffres, signe inclus

1.11.2 La fonction de saisie scanf 

Page 70: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 70/238

Mar 16, 2009 F.KHOUKHI 70

Exemple:

#include <stdio.h>

main()

{

int i;

printf("entrez un entier sous forme hexadecimale i = ");scanf("%x",&i);

printf("i = %d\n",i);

}

Si on entre au clavier la valeur 1a, le programme affiche i = 26.

1.11.2 format de saisie scanf représentation de la donnée saisietype d'objet pointéformat

Page 71: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 71/238

Mar 16, 2009 F.KHOUKHI 71

chaîne de caractèreschar*%s

caractèrechar %c

flottante virgule fixe ou notation exponentiellelong double%Lg

flottante virgule fixe ou notation exponentielledouble%lg

flottante virgule fixe ou notation exponentiellefloat%g

flottante notation exponentiellelong double%Le

flottante notation exponentielledouble%le

flottante notation exponentiellefloat%e

flottante virgule fixelong double%Lf 

flottante virgule fixedouble%lf 

flottante virgule fixefloat%f 

hexadécimalelong int%lx

hexadécimaleshort int%hx

hexadécimaleint%x

octalelong int%lo

octaleshort int%ho

octaleint%o

décimale non signéeunsigned long int%lu

décimale non signéeunsigned short int%hu

décimale non signéeunsigned int%u

décimale signéelong int%ld

décimale signéeshort int%hd

décimale signéeint%d

représentation de la donnée saisietype d objet pointéformat

1.11.3 Impression et lecture de caractères

Page 72: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 72/238

Mar 16, 2009 F.KHOUKHI 72

• Les fonctions getchar et putchar permettentrespectivement de lire et d'imprimer des caractères. Ils'agit de fonctions d'entrées-sorties non formatées.

• La fonction getchar retourne un int correspondant aucaractère lu. Pour mettre le caractère lu dans unevariable caractère, on écrit caractere = getchar();

• Lorsqu'elle détecte la fin de fichier, elle retourne l'entier EOF (End Of File), valeur définie dans la librairie stdio.h.

En général, la constante EOF vaut -1• La fonction putchar écrit caractere sur la sortie

standard : putchar(caractere);• Elle retourne un int correspondant à l'entier lu ou à la

constante EOF en cas d'erreur.

1.11.3 Impression et lecture de caractères

Page 73: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 73/238

Mar 16, 2009 F.KHOUKHI 73

Exemple:

#include <stdio.h>main()

{ char c;

while ((c = getchar()) != EOF)putchar(c);

}

1.12 Les conventions d'écriture d'unprogramme C

Page 74: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 74/238

Mar 16, 2009 F.KHOUKHI 74

programme C• On n'écrit qu'une seule instruction par ligne : le point

virgule d'une instruction ou d'une déclaration est

toujours le dernier caractère de la ligne.• Les instructions sont disposées de telle façon que lastructure modulaire du programme soit mise enévidence. En particulier, une accolade ouvrantemarquant le début d'un bloc doit être seule sur sa ligneou placée à la fin d'une ligne. Une accolade fermante

est toujours seule sur sa ligne.• On laisse un blanc• entre les mots-clefs if, while, do, switch et la

parenthèse ouvrante qui suit,• après une virgule,

• de part et d'autre d'un opérateur binaire.• On ne met pas de blanc entre un opérateur unaire et

son opérande, ni entre les deux caractères d'unopérateur d'affectation composée.

References

Page 75: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 75/238

Mar 16, 2009 F.KHOUKHI 75

References • Braquelaire (J.-P.). -- Méthodologie de la programmation

en C . --

Dunod, 2000, troisième édition.• Delannoy (C.). -- Programmer en langage C . -- Eyrolles, 1992. • Kernighan (B.W.) et Richie (D.M.). -- The C programming

language. -- Prentice Hall, 1988, seconde édition.

Les tableaux

Page 76: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 76/238

Mar 16, 2009 76

• Un tableau est un ensemble fini d'éléments de même type,stockés en mémoire à des adresses contiguës.

• La déclaration d'un tableau à une dimension se fait de lafaçon suivante : type nom-du-tableau [nombre-éléments];

Exemple:• int tab[10]; indique que tab est un tableau de 10 éléments

de type int. Cette déclaration alloue donc en mémoire pour l'objet tab un espace de 10 × 4 octets consécutifs.

#define N 10main()

{ int tab[N]; int i;...for (i = 0; i < N; i++)printf("tab[%d] = %d\n",i,tab[i]);}

Page 77: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 77/238

Mar 16, 2009 F.KHOUKHI 77

Chapitre 2Les types composésEn Langage C

F.KHOUKHI

Les tableaux• On peut initialiser un tableau lors de sa d claration par une liste

Page 78: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 78/238

Mar 16, 2009 78

On peut initialiser un tableau lors de sa d claration par une listede constantes de la façon suivante :

• type nom-du-tableau[N] = {constante-1,constante-2,...,constante-N};

• Exemple#define N 4int tab[N] = {1, 2, 3, 4};main(){ int i;for (i = 0; i < N; i++)printf("tab[%d] = %d\n",i,tab[i]);

}Si le nombre de données dans la liste d'initialisation est inférieur à la

dimension du tableau, seuls les premiers éléments serontinitialisés. Les autres éléments seront mis à zéro si le tableau estune variable globale (extérieure à toute fonction) ou une variablelocale de classe de mémorisation static

De la même manière un tableau de caractères peut être initialisé par une liste de caractères, mais aussi par une chaîne de caractèreslittérale. Notons que le compilateur complète toute chaîne decaractères avec un caractère nul '\0'. Il faut donc que le tableau aitau moins un élément de plus que le nombre de caractères de lachaîne littérale.

Les tableauxE l

Page 79: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 79/238

Mar 16, 2009 79

Exemple#define N 8char tab[N] = "exemple";

main(){int i;for (i = 0; i < N; i++)printf("tab[%d] = %c\n",i,tab[i]);

}Lors d'une initialisation, il est également possible de ne pas

spécifier le nombre d'éléments du tableau. Par défaut, ilcorrespondra au nombre de constantes de la listed'initialisation

Exemple:

char tab[] = "exemple";main(){ int i;printf("Nombre de caracteres du tableau =

%d\n",sizeof(tab)/sizeof(char));}

Les tableaux à 2 dimension

Page 80: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 80/238

Mar 16, 2009 80

on peut d clarer un tableau plusieurs dimensions. Par exemple,pour un tableau à deux dimensions :

type nom-du-tableau[nombre-lignes][nombre-colonnes]

En fait, un tableau à deux dimensions est un tableauunidimensionnel dont chaque élément est lui-même un tableau.On accède à un élément du tableau par l'expression``tableau[i][j]''. Pour initialiser un tableau à plusieurs dimensionsà la compilation, on utilise une liste dont chaque élément est uneliste de constantes

#define M 2#define N 3int tab[M][N] = {{1, 2, 3}, {4, 5, 6}};main(){ int i, j;

for (i = 0 ; i < M; i++){ for (j = 0; j < N; j++)printf("tab[%d][%d]=%d\n",i,j,tab[i][j]);

}}

Les structures• Une structure est une suite finie d'objets de types différents

Page 81: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 81/238

Mar 16, 2009 81

• Une structure est une suite finie d objets de types différents.Contrairement aux tableaux, les différents éléments d'unestructure n'occupent pas nécessairement des zonescontiguës en mémoire. Chaque élément de la structure,appelé membre ou champ, est désigné par un identificateur.

• struct modele {type-1 membre-1; type-2 membre-2 ; ... type-n membre-n; };

• Pour déclarer un objet de type structure correspondant aumodèle précédent, on utilise la syntaxe:struct modele objet ;

• ou bien, si le modèle n'a pas été déclaré au préalable :

struct modele {type-1 membre-1; type-2 membre-2 ; ... type-n membre-n; }objet ;

• On accède aux différents membres d'une structure grâce àl'opérateur membre de structure, noté ``.''. Le i-ème membrede objet est désigné par l'expression :

• objet .membre-i  

Exemple de structure

Page 82: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 82/238

Mar 16, 2009 82

p• include <math.h>struct complexe

{ double reelle;double imaginaire; };

main(){ struct complexe z; double norme;

...norme = sqrt(z.reelle * z.reelle + z.imaginaire *z.imaginaire);

printf("norme de (%f + i %f) = %f \n",z.reelle,z.imaginaire,norme);

}Les règles d'initialisation d'une structure lors de sadéclaration sont les mêmes que pour les tableaux. Onécrit par exemple :struct complexe z = {2. , 2.};

Les champs de bits

Page 83: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 83/238

Mar 16, 2009 83

p• Il est possible en C de spécifier la longueur des champs d'une

structure au bit près si ce champ est de type entier (int ouunsigned int). Cela se fait en précisant le nombre de bits du

champ avant le ; qui suit sa déclaration. Par exemple, lastructure suivante:struct registre{ unsigned int actif : 1;unsigned int valeur : 31;};

possède deux membres, actif qui est codé sur un seul bit, et valeur qui est codé sur 31 bits. Tout objet de type struct registre estdonc codé sur 32 bits. Toutefois, l'ordre dans lequel les champssont placés à l'intérieur de ce mot de 32 bits dépend del'implémentation.Le champ actif de la structure ne peut prendre que les valeurs 0

et 1. Aussi, si r est un objet de type struct registre, l'opérationr.actif += 2; ne modifie pas la valeur du champ.La taille d'un champ de bits doit être inférieure au nombre debits d'un entier. Notons enfin qu'un champ de bits n'a pasd'adresse ; on ne peut donc pas lui appliquer l'opérateur &.

Les Unions

Page 84: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 84/238

Mar 16, 2009 84

Les Unions• Une union désigne un ensemble de variables de types

différents susceptibles d'occuper  alternativement  unemême zone mémoire. Une union permet donc de définir un objet comme pouvant être d'un type au choix parmiun ensemble fini de types. Si les membres d'une unionsont de longueurs différentes, la place réservée enmémoire pour la représenter correspond à la taille dumembre le plus grand.

• Les déclarations et les opérations sur les objets de typeunion sont les mêmes que celles sur les objets de type

struct. Dans l'exemple suivant, la variable hier de typeunion jour peut être soit un entier, soit un caractère

Exemple d’Union

Page 85: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 85/238

Mar 16, 2009 85

punion jour { char lettre;

int numero;

};main(){ union jour hier, demain;hier.lettre = 'J';

printf("hier = %c\n",hier.lettre);hier.numero = 4;demain.numero = (hier.numero + 2) % 7;

printf("demain = %d\n",demain.numero);

}Les unions peuvent être utiles lorsqu'on a besoin

de voir un objet sous des types différents (maisen général de même taille)

Exemple d’Union

Page 86: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 86/238

Mar 16, 2009 86

pstruct coordonnees { unsigned int x;

unsigned int y;};

union point {struct coordonnees coord;unsigned long mot;};

main(){ union point p1, p2, p3;p1.coord.x = 0xf;p1.coord.y = 0x1;

p2.coord.x = 0x8;p2.coord.y = 0x8;p3.mot = p1.mot ^ p2.mot;printf("p3.coord.x = %x \t p3.coord.y = %x\n",

p3.coord.x, p3.coord.y);

Les énumérationsLes énumérations permettent de définir un type par la liste des

Page 87: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 87/238

Mar 16, 2009 87

Les énumérations permettent de définir un type par la liste desvaleurs qu'il peut prendre. Un objet de type énumération estdéfini par le mot-clef enum et un identificateur de modèle,suivis de la liste des valeurs que peut prendre cet objet : 

enum modele {constante-1, constante-2 ,...,constante-n};Exemple:main(){ enum booleen {faux, vrai};

enum booleen b;

b = vrai;printf("b = %d\n",b);}En réalité, les objets de type enum sont représentés comme des int.

Les valeurs possibles constante-1, constante-2,...,constante-n sontcodées par des entiers de 0 à n-1. Par exemple, le type enum

booleen défini dans le programme suivant associe l'entier 0 à lavaleur faux et l'entier 1 à la valeur vrai.

Définition de types composés avec typedef  Pour alléger l'écriture des programmes on peut affecter un

Page 88: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 88/238

Mar 16, 2009 88

Pour alléger l écriture des programmes, on peut affecter unnouvel identificateur à un type composé à l'aide detypedef : typedef type synonyme;

Exemple:struct complexe{ double reelle;

double imaginaire;};

typedef struct complexe complexe;

main(){

complexe z;...

}

Page 89: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 89/238

Mar 16, 2009 F.KHOUKHI 89

Chapitre 3

Les pointeurs

Introduction

Page 90: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 90/238

Mar 16, 2009 F.KHOUKHI 90

Introduction• Toute variable manipulée dans un

programme est stockée quelque part enmémoire centrale.• Cette mémoire est constituée d'octets qui

sont identifiés de manière univoque par un

numéro qu'on appelle adresse.• Pour retrouver une variable, il suffit donc

de connaître l'adresse de l'octet où elle est

stockée (ou, s'il s'agit d'une variable quirecouvre plusieurs octets contigus,l'adresse du premier de ces octets).

Introduction

Page 91: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 91/238

Mar 16, 2009 F.KHOUKHI 91

• Pour des raisons évidentes de lisibilité, on

désigne souvent les variables par desidentificateurs, et non par leur adresse.C'est le compilateur qui fait alors le lien

entre l'identificateur d'une variable et sonadresse en mémoire. Toutefois, il estparfois très pratique de manipuler 

directement une variable par son adresse.

3.1 Adresse et valeur d'un objet

Page 92: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 92/238

Mar 16, 2009 F.KHOUKHI 92

j

• On appelle Lvalue (left value) tout objet

pouvant être placé à gauche d'unopérateur d'affectation.

• Une Lvalue est caractérisée par :

• son adresse, c'est-à-dire l'adresse-mémoire à partir de laquelle l'objet eststocké ;

• sa valeur, c'est-à-dire ce qui est stocké àcette adresse.

3.1 Adresse et valeur d'un objet

Page 93: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 93/238

Mar 16, 2009 F.KHOUKHI 93

• Exemple• int i = 3, j = i;

• Si le compilateur a placé la variable i à l'adresse 4831836000en mémoire, et la variable j à l'adresse 4831836004, on a 

34831836004 j

34831836000i

valeur adresseobjet

Deux variables différentes ont des adressesdifférentes.

L'affectation i = j; n'opère que sur les valeursdes variables. Les variables i et j étant de typeint,

elles sont stockées sur 4 octets. Ainsi la valeur 

de i est stockée sur les octets d'adresse4831836000 à 4831836003.

3.1 Adresse et valeur d'un objet

Page 94: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 94/238

Mar 16, 2009 F.KHOUKHI 94

• L'adresse d'un objet étant un numérod'octet en mémoire, il s'agit d'un entier quelque soit le type de l'objet considéré.

• Le format interne de cet entier (16 bits, 32bits ou 64 bits) dépend des architectures.

• Sur un DEC alpha, par exemple, une

adresse a toujours le format d'un entier long (64 bits)

3.1 Adresse et valeur d'un objet

Page 95: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 95/238

Mar 16, 2009 F.KHOUKHI 95

3.1 Adresse et valeur d un objet

L'opérateur & permet d'accéder à l'adresse d'unevariable.

Toutefois &i n'est pas une Lvalue mais uneconstante :

on ne peut pas faire figurer &i à gauche d'unopérateur d'affectation.

Pour pouvoir manipuler des adresses, on doitdonc recourir un nouveau type d'objets, lespointeurs.

3.2 Notion de pointeur 

Page 96: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 96/238

Mar 16, 2009 F.KHOUKHI 96

• Un  pointeur est un objet (Lvalue) dont la valeur est égale à l'adressed'un autre objet. On déclare un pointeur par l'instruction :

type *nom-du-pointeur ;

où type est le type de l'objet pointé.

Cette déclaration déclare un identificateur, nom-du-pointeur ,associé à un objet dont la valeur est l'adresse d'un autreobjet de type type.

L'identificateur nom-du-pointeur est donc en quelque sorte unidentificateur d'adresse.Comme pour n'importe quelle Lvalue, sa valeur estmodifiable.

3.2 Notion de pointeur 

Page 97: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 97/238

Mar 16, 2009 F.KHOUKHI 97

• Un pointeur est un objet (Lvalue) dont la valeur est égale àl'adresse

• Même si la valeur d'un pointeur est toujours un entier (éventuellement un entier long), le type d'un pointeur dépend du type de l'objet vers lequel il pointe.

• Cette distinction est indispensable à l'interprétation de lavaleur d'un pointeur.

• En effet, pour un pointeur sur un objet de type char, lavaleur donne l'adresse de l'octet où cet objet est stocké.

• Par contre, pour un pointeur sur un objet de type int, lavaleur donne l'adresse du premier des 4 octets où l'objet

est stocké.• Dans l'exemple suivant, on définit un pointeur p qui pointe

vers un entier i :

Page 98: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 98/238

3.2 Notion de pointeur 

Page 99: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 99/238

Mar 16, 2009 F.KHOUKHI 99

main()

{ int i = 3, j = 6; int *p1, *p2;

p1 = &i;

p2 = &j;

*p1 = *p2;

• Cela signifie en particulier que toute modification de *p

modifie i. Ainsi, si l'on ajoute l'instruction *p = 0; à la fin duprogramme précédent, la valeur de i devient nulle.

On peut donc dans un programme manipuler à la fois lesobjets p et *p. Ces deux manipulations sont très

différentes. Comparons par exemple les deuxprogrammes suivants :main()

{ int i = 3, j = 6; int *p1, *p2; p1= &i;

p2 = &j;

p1 = p2;

3.2 Notion de pointeur 

Page 100: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 100/238

Mar 16, 2009 F.KHOUKHI 100

Avant la dernière affectation de chacun de ces programmes, on estdans une configuration du type :

48318360044831835992p2

48318360004831835984p1

64831836004 j

34831836000i

valeur adresseobjet

Après l'affectation *p1 = *p2; du premier programme, ona

48318360044831835992p2

48318360004831835984p1

64831836004 j64831836000i

valeur adresseobjet

3.2 Notion de pointeur 

Page 101: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 101/238

Mar 16, 2009 F.KHOUKHI 101

p

Par contre, l'affectation p1 = p2 du second programme, conduit à la situation :

48318360044831835992p2

48318360044831835984p1

64831836004 j

34831836000i

valeur adresseobjet

3.3 Arithmétique des pointeurs

Page 102: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 102/238

Mar 16, 2009 F.KHOUKHI 102

• La valeur d'un pointeur étant un entier, on peut luiappliquer un certain nombre d'opérateurs arithmétiques

classiques. Les seules opérations arithmétiques validessur les pointeurs sont :

• l'addition d'un entier à un pointeur. Le résultat est unpointeur de même type que le pointeur de départ ;

• la soustraction d'un entier à un pointeur. Le résultat estun pointeur de même type que le pointeur de départ ;

•la différence de deux pointeurs pointant tous deux versdes objets de même type. Le résultat est un entier.

• Notons que la somme de deux pointeurs n'est pasautorisée.

3 3 Arithmétique des pointeurs

Page 103: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 103/238

Mar 16, 2009 F.KHOUKHI 103

3.3 Arithmétique des pointeurs

• Si i est un entier et p est un pointeur sur un objet de type type, l'expression p + idésigne un pointeur sur un objet de typetype dont la valeur est égale à la valeur dep incrémentée de i * sizeof(type).

• Il en va de même pour la soustraction d'unentier à un pointeur, et pour les opérateurs

d'incrémentation et de décrémentation ++et --. Par exemple, le programme

3.3 Arithmétique des pointeurs

Page 104: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 104/238

Mar 16, 2009 F.KHOUKHI 104

• main() • { int i = 3; int *p1, *p2; p1 = &i; p2 = p1 + 1;

• printf("p1 = %ld \t p2 = %ld\n",p1,p2);• }

• affiche p1 = 4831835984 p2 = 4831835988.

Par contre, le même programme avec des pointeurs sur des objets de type double :• main()• { double i = 3; double *p1, *p2; p1 = &i; p2 = p1 + 1;•

printf("p1 = %ld \t p2 = %ld\n",p1,p2);• }

• affiche p1 = 4831835984 p2 = 4831835992

3.3 Arithmétique des pointeurs

Page 105: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 105/238

Mar 16, 2009 F.KHOUKHI 105

• Les opérateurs de comparaison sontégalement applicables aux pointeurs, àcondition de comparer des pointeurs quipointent vers des objets de même type.

• L'utilisation des opérations arithmétiquessur les pointeurs est particulièrement utilepour parcourir des tableaux.

• Ainsi, le programme suivant imprime les

éléments du tableau tab dans l'ordrecroissant puis décroissant des indices.

3.3 Arithmétique des pointeurs

Page 106: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 106/238

Mar 16, 2009 F.KHOUKHI 106

#define N 5int tab[5] = {1, 2, 6, 0, 7};

main(){ int *p;printf("\n ordre croissant:\n");for (p = &tab[0]; p <= &tab[N-1]; p++)

printf(" %d \n",*p);printf("\n ordre decroissant:\n");for (p = &tab[N-1]; p >= &tab[0]; p--)printf(" %d \n",*p);}

• Si p et q sont deux pointeurs sur des objets de typetype, l'expression p - q désigne un entier dont lavaleur est égale à (p - q)/sizeof(type) .

3.4 Allocation dynamique

Page 107: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 107/238

Mar 16, 2009 F.KHOUKHI 107

• Avant de manipuler un pointeur, et notammentde lui appliquer l'opérateur d'indirection *, il fautl'initialiser. Sinon, par défaut, la valeur dupointeur est égale à une constante symboliquenotée NULL définie dans stdio.h.

• En général, cette constante vaut 0. Le test p ==NULL permet de savoir si le pointeur p pointevers un objet.On peut initialiser un pointeur p par une

affectation sur p.

3.4 Allocation dynamique

Page 108: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 108/238

Mar 16, 2009 F.KHOUKHI 108

• Par exemple, on peut affecter à p l'adressed'une autre variable.

• Il est également possible d'affecter directementune valeur à *p.

• Mais pour cela, il faut d'abord réserver à *p un

espace-mémoire de taille adéquate.• L'adresse de cet espace-mémoire sera la valeur de p.

• Cette opération consistant à réserver un espace-

mémoire pour stocker l'objet pointé s'appelleallocation dynamique. Elle se fait en C par lafonction malloc de la librairie standard stdlib.h.Sa syntaxe est: malloc(nombre-octets)

3.4 Allocation dynamique• Cette fonction retourne un pointeur de type char *

Page 109: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 109/238

Mar 16, 2009 F.KHOUKHI 109

p yppointant vers un objet de taille nombreoctets octets.

• Pour initialiser des pointeurs vers des objets qui ne sont

pas de type char, il faut convertir le type de la sortie dela fonction malloc à l'aide d'un cast.• L'argument nombre-octets est souvent donné à l'aide de

la fonction sizeof() qui renvoie le nombre d'octets utiliséspour stocker un objet.

Ainsi, pour initialiser un pointeur vers un entier,• on écrit :• #include <stdlib.h>• int *p;• p = (int*)malloc(sizeof(int));

• On aurait pu écrire égalementp = (int*)malloc(4);puisqu'un objet de type int est stocké sur 4 octets. Maison préférera la première écriture qui a l'avantage d'êtreportable.

#include <stdio.h>#include <stdlib h>

3.4 Allocation dynamique

Page 110: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 110/238

Mar 16, 2009 F.KHOUKHI 110

#include <stdlib.h>main()

{ int i = 3; int *p;printf("valeur de p avant initialisation = %ld\n",p);p = (int*)malloc(sizeof(int));

printf("valeur de p apres initialisation = %ld\n",p);*p = i;

printf("valeur de *p = %d\n",*p);}• définit un pointeur p sur un objet *p de type int, et affecte

à *p la valeur de la variable i. Il imprime à l'écran : valeur de p avant initialisation = 0

• valeur de p apres initialisation = 5368711424 valeur de*p = 3

Avant l'allocation dynamique, on se 34831836000i

valeur adresseobjet

Page 111: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 111/238

Mar 16, 2009 F.KHOUKHI 111

y qtrouve dans la configuration

04831836004p

34831836000

A ce stade, *p n'a aucun sens. En particulier,

toute manipulation de la variable *pgénérerait une violation mémoire, détectableà l'exécution par le message d'erreur Segmentation fault.L'allocation dynamique a pour résultatd'attribuer une valeur à p et de réserver à

cette adresse un espace-mémoire composéde 4 octets pour stocker la valeur de *p. Ona alors

? (int)5368711424*p

53687114244831836004p

34831836000i

valeur adresseobjet

*p est maintenant définie mais sa valeur n'est pas initialisée. Cela signifie que *ppeut valoir n'importe quel entier (celui

qui se trouvait précédemment à cetteadresse). L'affectation *p = i; a enfinpour résultat d'affecter à *p la valeur dei. A la fin du programme, on a donc

35368711424*p

53687114244831836004p

34831836000i

valeur adresseobjet

3.4 Allocation dynamique

Page 112: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 112/238

Mar 16, 2009 F.KHOUKHI 112

main() { int i = 3; int *p; p = &i; } qui correspond à lasituation

34831836000*p

48318360004831836004p

34831836000i

valeur adresseobjet

Dans ce dernier cas, les variables i et *p sont identiques (elles ont lamême adresse) ce qui implique que toute modification de l'une modifiel'autre. Ceci n'était pas vrai dans l'exemple précédent où *p et i avaient

la même valeur mais des adresses différentes.On remarquera que le dernier programme ne nécessite pas d'allocationdynamique puisque l'espace-mémoire à l'adresse &i est déjà réservépour un entier.

La fonction malloc permet également d'allouer un espacepour plusieurs objets contigus en mémoire. On peut

Page 113: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 113/238

Mar 16, 2009 F.KHOUKHI 113

p p j g pécrire par exemple

#include <stdio.h>

#include <stdlib.h>main(){

int i = 3;

int j = 6;int *p;p = (int*)malloc(2 * sizeof(int));*p = i;*(p + 1) = j;

printf("p = %ld \t *p = %d \t p+1 = %ld \t *(p+1) = %d\n",p,*p,p+1,*(p+1));

}

On a ainsi réservé, à l'adresse donnée par la valeur de p, 8octets en mémoire, qui permettent de stocker 2 objets de

Page 114: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 114/238

Mar 16, 2009 F.KHOUKHI 114

jtype int. Le programme affiche

p = 5368711424 *p = 3 p+1 = 5368711428 *(p+1) = 6 .

La fonction calloc de la librairie stdlib.h a le même rôle quela fonction malloc mais elle initialise en plus l'objet pointé*p à zéro. Sa syntaxe est

calloc(nb-objets,taille-objets) Ainsi, si p est de type int*,

l'instructionp = (int*)calloc(N,sizeof(int));est strictement équivalente àp = (int*)malloc(N * sizeof(int));

for (i = 0; i < N; i++)*(p + i) = 0;L'emploi de calloc est simplement plus rapide

• Enfin, lorsque l'on n'a plus besoin de l'espace-mémoire allo é d namiq ement (c'est à dire

Page 115: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 115/238

Mar 16, 2009 F.KHOUKHI 115

mémoire alloué dynamiquement (c'est-à-direquand on n'utilise plus le pointeur p), il faut

libérer cette place en mémoire. Ceci se fait àl'aide de l'instruction free qui a pour syntaxefree(nom-du-pointeur );

• A toute instruction de type malloc ou calloc doitêtre associée une instruction de type free.

3 5 Pointeurs et tableaux

Page 116: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 116/238

Mar 16, 2009 F.KHOUKHI 116

3.5 Pointeurs et tableaux

• L'usage des pointeurs en C est, en grandepartie, orienté vers la manipulation destableaux.

3.5.1 Pointeurs et tableaux à une dimension

T t t bl C t f it i t t t

Page 117: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 117/238

Mar 16, 2009 F.KHOUKHI 117

• Tout tableau en C est en fait un pointeur constant.• Dans la déclaration int tab[10]; tab est un pointeur 

constant (non modifiable) dont la valeur est l'adresse dupremier élément du tableau.• Autrement dit, tab a pour valeur &tab[0]. On peut donc

utiliser un pointeur initialisé à tab pour parcourir leséléments du tableau.

• #define N 5• int tab[5] = {1, 2, 6, 0, 7};• main()• { int i; int *p; p = tab;• for (i = 0; i < N; i++)• { printf(" %d \n",*p);• p++;• }• }

3.5.1 Pointeurs et tableaux à une dimension

O èd à l'élé t d'i di i d t bl t b â à

Page 118: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 118/238

Mar 16, 2009 F.KHOUKHI 118

• On accède à l'élément d'indice i du tableau tab grâce àl'opérateur d'indexation [], par l'expression tab[i]. Cetopérateur d'indexation peut en fait s'appliquer à toutobjet p de type pointeur. Il est lié à l'opérateur d'indirection * par la formule p[i] = *(p + i)

• Pointeurs et tableaux se manipulent donc exactement demême manière. Par exemple, le programme précédentpeut aussi s'écrire :

#define N 5int tab[5] = {1, 2, 6, 0, 7};main()

{ int i; int *p;

p = tab;for (i = 0; i < N; i++)printf(" %d \n", p[i]);

}

3.5.1 Pointeurs et tableaux à une dimensionToutefois, la manipulation de tableaux, et non de pointeurs, possèdecertains inconvénients dûs au fait qu'un tableau est un pointeur constant Ainsi

Page 119: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 119/238

Mar 16, 2009 F.KHOUKHI 119

constant. Ainsion ne peut pas créer de tableaux dont la taille est une variable du

programme,

on ne peut pas créer de tableaux bidimensionnels dont les lignes n'ontpas toutes le même nombre d'éléments.

Ces opérations deviennent possibles dès que l'on manipule despointeurs alloués dynamiquement. Ainsi, pour créer un tableaud'entiers à n éléments où n est une variable du programme, on écrit

#include <stdlib.h>main(){int n;int *tab;

 

...tab = (int*)malloc(n * sizeof(int));...

free(tab);}

3.5.1 Pointeurs et tableaux à une dimensionSi on veut en plus que tous les éléments du tableau tab

soient initialisés à zéro, on remplace l'allocation

Page 120: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 120/238

Mar 16, 2009 F.KHOUKHI 120

soient initialisés à zéro, on remplace l allocationdynamique avec malloc par :tab = (int*)calloc(n,sizeof(int));

Les éléments de tab sont manipulés avec l'opérateur d'indexation [], exactement comme pour les tableaux.

• Les deux différences principales entre un tableau et unpointeur sont

• un pointeur doit toujours être initialisé, soit par uneallocation dynamique, soit par affectation d'uneexpression adresse, par exemple p = &i ;

• un tableau n'est pas une Lvalue ; il ne peut donc pasfigurer à gauche d'un opérateur d'affectation. Enparticulier, un tableau ne supporte pas l'arithmétique (onne peut pas écrire tab++;).

3.5.2 Pointeurs et tableaux à plusieurs dimensions

Page 121: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 121/238

Mar 16, 2009 F.KHOUKHI 121

Un tableau à deux dimensions est, par 

définition, un tableau de tableaux.Il s'agit donc en fait d'un pointeur vers un

pointeur.

Considérons le tableau à deux dimensionsdéfini par :

int tab[M][N];

3.5.2 Pointeurs et tableaux à plusieurs dimensions

tab est un pointeur qui pointe vers un objet

Page 122: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 122/238

Mar 16, 2009 F.KHOUKHI 122

tab est un pointeur, qui pointe vers un objetlui-même de type pointeur d'entier.

tab a une valeur constante égale à l'adressedu premier élément du tableau, &tab[0][0].

De même tab[i], pour i entre 0 et M-1, estun pointeur constant vers un objet de typeentier, qui est le premier élément de laligne d'indice i. tab[i] a donc une valeur 

constante qui est égale à &tab[i][0].

3.5.2 Pointeurs et tableaux à plusieurs dimensions

Page 123: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 123/238

Mar 16, 2009 F.KHOUKHI 123

• Exactement comme pour les tableaux à

une dimension, les pointeurs de pointeursont de nombreux avantages sur lestableaux multi-dimensionnés.

On déclare un pointeur qui pointe sur unobjet de type type * (deux dimensions) dela même manière qu'un pointeur, c'est-à-dire type **nom-du-pointeur ;

Page 124: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 124/238

3.5.2 Pointeurs et tableaux à plusieurs dimensions

main()

Page 125: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 125/238

Mar 16, 2009 F.KHOUKHI 125

{ int k, n; int **tab;

tab = (int**)malloc(k * sizeof(int*));for (i = 0; i < k; i++)tab[i] = (int*)malloc(n * sizeof(int));

....for (i = 0; i < k; i++)free(tab[i]);

free(tab);}

Page 126: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 126/238

Page 127: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 127/238

3.5.3 Pointeurs et chaînes de caractères • On a vu précédemment qu'une chaîne de

Page 128: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 128/238

Mar 16, 2009 F.KHOUKHI 128

On a vu précédemment qu une chaîne decaractères était un tableau à une dimension

d'objets de type char, se terminant par lecaractère nul '\0'. On peut donc manipuler toutechaîne de caractères à l'aide d'un pointeur sur un objet de type char. On peut faire subir à unechaîne définie par char *chaine;

• des affectations comme• chaine = "ceci est une chaine";• et toute opération valide sur les pointeurs,

comme l'instruction chaine++;. Ainsi, le

programme suivant imprime le nombre decaractères d'une chaîne (sans compter lecaractère nul).

3.5.3 Pointeurs et chaînes de caractères #include <stdio.h>

Page 129: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 129/238

Mar 16, 2009 F.KHOUKHI 129

main()

{ int i; char *chaine;

chaine = "chaine de caracteres";

for (i = 0; *chaine != '\0'; i++)chaine++;

printf("nombre de caracteres =

%d\n",i);} 

3.5.3 Pointeurs et chaînes de caractères La fonction donnant la longueur d'une chaîne de

caractères définie dans la librairie standard

Page 130: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 130/238

Mar 16, 2009 F.KHOUKHI 130

caractères, définie dans la librairie standardstring.h, procède de manière identique. Il s'agit

de la fonction strlen dont la syntaxe eststrlen(chaine); 

où chaine est un pointeur sur un objet de typechar.

Cette fonction renvoie un entier dont la valeur estégale à la longueur de la chaîne passée enargument (moins le caractère '\0').

L'utilisation de pointeurs de caractère et non de

tableaux permet par exemple de créer unechaîne correspondant à la concaténation dedeux chaînes de caractères :

#include <stdio.h>#include <stdlib.h>#include <string h>

Page 131: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 131/238

Mar 16, 2009 F.KHOUKHI 131

#include <string.h>main()

{ int i; char *chaine1, *chaine2, *res, *p;chaine1 = "chaine ";chaine2 = "de caracteres";res = (char*)malloc((strlen(chaine1) +

strlen(chaine2)) * sizeof(char));p = res;for (i = 0; i < strlen(chaine1); i++)*p++ = chaine1[i];for (i = 0; i < strlen(chaine2); i++)*p++ = chaine2[i];printf("%s\n",res);

}

On remarquera l'utilisation d'un pointeur intermédiaire p qui est indispensable dès

Page 132: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 132/238

Mar 16, 2009 F.KHOUKHI 132

que l'on fait des opérations de type

incrémentation.En effet, si on avait incrémenté directement

la valeur de res, on aurait évidemment

``perdu'' la référence sur le premier caractère de la chaîne.

Par exemple,

#include <stdio.h>#include <stdlib.h>#include <string.h>

Page 133: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 133/238

Mar 16, 2009 F.KHOUKHI 133

main(){ int i; char *chaine1, *chaine2, *res;chaine1 = "chaine ";chaine2 = "de caracteres";

res = (char*)malloc((strlen(chaine1) + strlen(chaine2)) *sizeof(char)); for (i = 0; i < strlen(chaine1); i++)

*res++ = chaine1[i];for (i = 0; i < strlen(chaine2); i++)*res++ = chaine2[i];printf("\nnombre de caracteres de res = %d\n",strlen(res));

}imprime la valeur 0, puisque res a été modifié au cours duprogramme et pointe maintenant sur le caractère nul.

3.6 Pointeurs et structures

• 3 6 1 Pointeur sur une structure

Page 134: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 134/238

Mar 16, 2009 F.KHOUKHI 134

• 3.6.1 Pointeur sur une structure

Contrairement aux tableaux, les objets detype structure en C sont des Lvalues. Ilspossèdent une adresse, correspondant àl'adresse du premier élément du premier 

membre de la structure.On peut donc manipuler des pointeurs sur 

des structures.

Ainsi, le programme suivant crée, à l'aided'un pointeur, un tableau d'objets de typestructure.

#include <stdlib.h>#include <stdio.h>struct eleve{ char nom[20];

3.6.1 Pointeur sur une structure

Page 135: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 135/238

Mar 16, 2009 F.KHOUKHI 135

int date;};

typedef struct eleve *classe;main() { int n, i; classe tab;printf("nombre d'eleves de la classe = ");scanf("%d",&n);tab = (classe)malloc(n * sizeof(struct eleve));

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

{ printf("\n saisie de l'eleve numero %d\n",i);printf("nom de l'eleve = ");scanf("%s",&tab[i].nom);printf("\n date de naissance JJMMAA = ");

scanf("%d",&tab[i].date);}

printf("\n Entrez un numero ");scanf("%d",&i); printf("\n Eleve numero %d:",i);printf("\n nom = %s",tab[i].nom);printf("\n date de naissance = %d\n",tab[i].date); free(tab); }

3.6.1 Pointeur sur une structure

• Si p est un pointeur sur une structure, on peut accéder à

Page 136: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 136/238

Mar 16, 2009 F.KHOUKHI 136

p p , pun membre de la structure pointé par l'expression

• (*p).membre• L'usage de parenthèses est ici indispensable car l'opérateur d'indirection * à une priorité plus élevée quel'opérateur de membre de structure. Cette notation peutêtre simplifiée grâce à l'opérateur pointeur de membre

de structure, noté ->. L'expression précédente eststrictement équivalente à

• p->membre• Ainsi, dans le programme précédent, on peut remplacer 

tab[i].nom et tab[i].date respectivement par (tab + i)->nom et (tab + i)->date.

Problème des tableaux

Page 137: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 137/238

Mar 16, 2009 F.KHOUKHI 137

•La structure la plus utilisée pour manipuler des

données est le tableau, qui contrairement aux listeschaînées, est implémenté de façon native dans lelangage C. Cependant dans certains cas, les tableauxne constituent pas la meilleure solution pour stocker et

manipuler les données. En effet, pour insérer unélément dans un tableau, il faut d'abord déplacer tousles éléments qui sont en amont de l'endroit où l'onsouhaite effectuer l'insertion, ce qui peut prendre untemps non négligeable proportionnel à la taille dutableau et à l'emplacement du futur élément. Il en estde même pour la suppression d'un élément; bien sûr ceci ne s'applique pas en cas d'ajout ou desuppression en fin de tableau. 

Avantage des listes chaînées

Page 138: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 138/238

Mar 16, 2009 F.KHOUKHI 138

Avec une liste chaînée, le temps d'insertion et de

suppression d'un élément est constant quelque soitl'emplacement de celui-ci et la taille de la liste.Elles sont aussi très pratiques pour réarranger lesdonnées, cet avantage est la conséquence directe

de la facilité de manipulation des éléments.Plus concrètement, une liste simplement chaînéeest en fait constituée de maillons ayant lapossibilité de pointer vers une donnée accessible

et modifiable par l'utilisateur ainsi qu'un lien vers lemaillon suivant.

Page 139: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 139/238

représentation d'une listechaînée en mémoire

Page 140: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 140/238

Mar 16, 2009 F.KHOUKHI 140

chaînée en mémoire.

Les opérations sur les listeschainées

Page 141: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 141/238

Mar 16, 2009 F.KHOUKHI 141

chainées

• Initialisation• Ajout d'un élément• Suppression d'un élément• Accès à l'élément suivant• Accès aux donées utilisateur • Accès au premier élément de la liste• Accès au dernier élément de la liste

• Calcul de la taille de la liste• Suppression de la liste entière

Les opérations sur les listeschainées

Page 142: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 142/238

Mar 16, 2009 F.KHOUKHI 142

chainées

• Le principal problème des listes simplementchaînées est l'absence de pointeur sur l'élémentprécédent du maillon, il est donc possible deparcourir la chaîne uniquement du début vers la

fin. Pour faciliter l'implémentation, nous allonsfaire quelques simplifications :• Sauvegarde du premier élément de la chaîne,

ceci permet de retourner au début de la liste,

• L'ajout s'effectue à la suite de l'élément spécifiéen paramètre de la fonction.

organisation de la liste chaînée

Page 143: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 143/238

Mar 16, 2009 F.KHOUKHI 143

3.6.2 Structures auto-référencéesListes Simplement Chainées

• On a souvent besoin en C de modèles de structure dont

Page 144: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 144/238

Mar 16, 2009 F.KHOUKHI 144

• On a souvent besoin en C de modèles de structure dontun des membres est un pointeur vers une structure de

même modèle. Cette représentation permet en particulier de construire des listes chaînées.• En effet, il est possible de représenter une liste d'éléments

de même type par un tableau (ou un pointeur).• Toutefois, cette représentation, dite contiguë, impose que

la taille maximale de la liste soit connue a priori (on abesoin du nombre d'éléments du tableau lors del'allocation dynamique).

• Pour résoudre ce problème, on utilise une représentationchaînée : l'élément de base de la chaîne est une structure

appelée cellule qui contient la valeur d'un élément de laliste et un pointeur sur l'élément suivant. Le dernier élément pointe sur la liste vide NULL.

• La liste est alors définie comme un pointeur sur le premier élément de la chaîne.

3.6.2 Structures auto-référencéesListes Simplement Chainées

Page 145: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 145/238

Mar 16, 2009 F.KHOUKHI 145

• Pour représenter une liste d'entiers sous formechaînée, on crée le modèle de structure cellulequi a deux champs :

• un champ valeur de type int, et un champ

suivant de type pointeur sur une struct cellule• . Une liste sera alors un objet de type pointeur sur une struct cellule.

• Grâce au mot-clef typedef, on peut définir le type

liste, synonyme du type pointeur sur une structcellule.

3.6.2 Structures auto-référencéesListes Simplement Chainées

struct cellule

Page 146: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 146/238

Mar 16, 2009 F.KHOUKHI 146

struct cellule{ int valeur;

struct cellule *suivant;};typedef struct cellule *liste;Un des avantages de la représentation chaînée est qu'il est très facile

d'insérer un élément à un endroit quelconque de la liste.Ainsi, pour insérer un élément en tête de liste, on utilise la fonction

suivante :liste insere(int element, liste Q){ liste L;L = (liste)malloc(sizeof(struct cellule));L->valeur = element;

L->suivant = Q;return(L);}

3.6.2 Structures auto-référencéesListes Simplement Chainées

Le programme suivant crée une liste d'entiers et l'imprime à l'écran :

Page 147: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 147/238

Mar 16, 2009 F.KHOUKHI 147

Le programme suivant crée une liste d entiers et l imprime à l écran :#include <stdlib.h>

#include <stdio.h>struct cellule{ int valeur;struct cellule *suivant;

};typedef struct cellule *liste;

liste insere(int element, liste Q)

{ liste L; L = (liste)malloc(sizeof(struct cellule));L->valeur = element;L->suivant = Q; return(L); } main() { liste L, P; L =

insere(1,insere(2,insere(3,insere(4,NULL))));printf("\n impression de la liste:\n");P = L; while (P != NULL)

{ printf("%d \t",P->valeur); P = P->suivant; }}On utilisera également une structure auto-référencée pour créer un arbre binaire :struct

noeud { int valeur; struct noeud *fils_gauche; struct noeud *fils_droit; }; typedef structnoeud *arbre;

CHAPITRE 3 (SUITE)

Page 148: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 148/238

Mar 16, 2009 F.KHOUKHI 148

CHAPITRE 3 (SUITE)LISTES CHAINEES

F.KHOUKHI2006

Dans cette présentation

Page 149: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 149/238

Mar 16, 2009 F.KHOUKHI 149

• Variations des listes• liste doublement chaînée

• liste chaînée circulairement

• Liste chaînée triée

Variations des listes: liste doublement chaînée

Page 150: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 150/238

Mar 16, 2009 F.KHOUKHI 150

• Liste simplement chaînée n'est pas efficace pour • Temps requis pour accès au dernier élément

• Difficile de remonter dans la liste

• exemple: traitement de texte

• Pointeurs next et previous• Symétrie: head et tail

Liste doublement chaînée

Page 151: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 151/238

Mar 16, 2009 F.KHOUKHI 151

• plus besoin de pointeurs null en début et fin, on peut tester • head->next==tail ou tail->previous==head => liste vide

• current->next==tail =>fin de la liste

• current ->previous == head => début de la liste

Liste doublement chaînée: insertion

Page 152: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 152/238

Mar 16, 2009 F.KHOUKHI 152

node *p = itr.current;p->prev->next = new node( x, p->prev, p );

p->prev = p->prev->next;

theSize++;

node *p = itr.current;p->prev->next = new node( x, p->prev, p );

p->prev = p->prev->next;

node *p = itr.current;p->prev->next = new node( x, p->prev, p );node *p = itr.current;

p

Liste doublement chaînée: suppression

Page 153: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 153/238

Mar 16, 2009 F.KHOUKHI 153

node *p = itr.current;iterator retVal( *this, p->next );

p->prev->next = p->next;

p->next->prev = p->prev;

delete p;

theSize--;

p

node *p = itr.current;iterator retVal( *this, p->next );

p->prev->next = p->next;

p->next->prev = p->prev;

node *p = itr.current;iterator retVal( *this, p->next );

p->prev->next = p->next;

node *p = itr.current;iterator retVal( *this, p->next );node *p = itr.current;

 retVal

Variations des listes: liste chaînée circulairement

Page 154: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 154/238

Mar 16, 2009 F.KHOUKHI 154

• Exemple: recherche avec "wraparound"

• Pas besoin de header:

• toute liste circulaire non vide aura un précédent et un suivant!

• seul cas spécial: liste vide

Variations des listes: liste chaînée triée 

Page 155: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 155/238

Mar 16, 2009 F.KHOUKHI 155

Seule modification:

• Changer la routine d'insertion pour que la position d'insertion soit par défaut labonne!

• Dériver de la classe llist:• routine d'insertion doit être virtual

#include "LinkedList.h"

// Commentaires habituels ...

template <class Object>

class SortedLList : public LList<Object> {

public:void insert( const Object & x );

void insert( const Object & x, const LListItr<Object> & p ){ insert(x);}

//Nécessaire pour éviter appels à la classe de base avec position: on

// ne fera qu'ignorer p

};

Variations des listes: liste chaînée triée 

Page 156: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 156/238

Mar 16, 2009 F.KHOUKHI 156

#include "SortLinkedList.h"

// Insert item x into the list.

template <class Object>

void SortedLList<Object>::insert( const Object & x )

{

LListItr<Object> prev = zeroth( );LListItr<Object> curr = first( );

while( !curr.isPastEnd( ) && curr.retrieve( ) < x )

{

prev.advance( );

curr.advance( );

}

LList<Object>::insert( x, prev );

}

 Implémentation de la classe "list" de la STLhttp://www.sgi.com/tech/stl/List.html,

#i l d tdlib h

Page 157: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 157/238

Mar 16, 2009 F.KHOUKHI 157

#include <stdlib.h>

// Incomplete class declarations for

// the const_iterator, iterator, and list,// because all these classes refer to each other.

template <class Object> class ConstListItr;

template <class Object> class ListItr;

template <class Object> class list;

// The basic doubly linked list node.

// Everything is private, and accessible only by the iterators and list classes.

template <class Object>

class ListNode {

Object data;

ListNode *prev;

ListNode *next;

ListNode(const Object & d = Object(), ListNode * p = NULL

, ListNode * n = NULL ) : data( d ), prev( p ), next( n ) { }

friend class ConstListItr<Object>;

friend class ListItr<Object>;

friend class list<Object>;

};

 Implémentation de la classe "list" de la STL

Page 158: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 158/238

Mar 16, 2009 F.KHOUKHI 158

template <class Object>

class list {

public:

typedef ListItr<Object> iterator;

typedef ConstListItr<Object> const_iterator;

list( );

~list( );

list( const list & rhs );const list & operator= ( const list & rhs );

iterator begin( );

const_iterator begin( ) const;

iterator end( );

const_iterator end( ) const;

int size( ) const;

bool empty( ) const;Object & front( );

const Object & front( ) const;

Object & back( );

const Object & back( ) const;

 Implémentation de la classe "list" de la STL

Page 159: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 159/238

Mar 16, 2009 F.KHOUKHI 159

void push_front( const Object & x );

void push_back( const Object & x );

void pop_front( );

void pop_back( );

iterator insert( iterator itr, const Object & x );

iterator erase( iterator itr );

iterator erase( iterator start, iterator end );

friend class ConstListItr<Object>;

friend class ListItr<Object>;

private:

typedef ListNode<Object> node;

int theSize;node *head;

node *tail;

void init( );

void makeEmpty( );

};

 Implémentation de la classe "list" de la STLtemplate <class Object>

class ConstListItr {

bli

Page 160: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 160/238

Mar 16, 2009 F.KHOUKHI 160

public:

ConstListItr( );

virtual ~ConstListItr( ) { }virtual const Object & operator* ( ) const;

ConstListItr & operator++ ( );

ConstListItr operator++ ( int );

ConstListItr & operator-- ( );

ConstListItr operator-- ( int );

bool operator== ( const ConstListItr & rhs ) const;

bool operator!= ( const ConstListItr & rhs ) const;

protected:

typedef ListNode<Object> node;

node *head;

node *current;

friend class list<Object>;

void assertIsInitialized( ) const;

void assertIsValid( ) const;

void assertCanAdvance( ) const;

void assertCanRetreat( ) const;

Object & retrieve( ) const;

ConstListItr( const list<Object> & source, node *p );

};

 Implémentation de la classe "list" de la STL

Page 161: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 161/238

Mar 16, 2009 F.KHOUKHI 161

template <class Object>

class ListItr : public ConstListItr<Object>

{

public:

ListItr( );

Object & operator* ( );

const Object & operator* ( ) const; 

ListItr & operator++ ( );

ListItr operator++ ( int );

ListItr & operator-- ( );

ListItr operator-- ( int );

protected:

typedef ListNode<Object> node;

friend class list<Object>;

ListItr( const list<Object> & source, node *p );

};

 Implémentation de la classe "list" de la STL

Page 162: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 162/238

Mar 16, 2009 F.KHOUKHI 162

template <class Object>

list<Object>::list( ) {init( );}

template <class Object>

void list<Object>::init( ) {

theSize = 0;

head = new node;

tail = new node;

head->next = tail;

tail->prev = head;

}

template <class Object>

list<Object>::~list( ) {

makeEmpty( );

delete head;

delete tail;

}

 Implémentation de la classe "list" de la STL

Page 163: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 163/238

Mar 16, 2009 F.KHOUKHI 163

template <class Object>

void list<Object>::makeEmpty( ) {while(!empty()) pop_front();}

template <class Object>

list<Object>::list( const list<Object> & rhs ) {init( ); *this = rhs;}

template <class Object>

const list<Object> & list<Object>::operator= ( const list & rhs ) {

if( this == &rhs ) return *this;makeEmpty( );

for(const_iterator itr=rhs.begin(); itr!=rhs.end(); ++itr) push_back(*itr);

return *this;

}

 Implémentation de la classe "list" de la STL

Page 164: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 164/238

Mar 16, 2009 F.KHOUKHI 164

// Return iterator representing beginning of list.

// Mutator version is first, then accessor version.

template <class Object>

list<Object>::iterator list<Object>::begin( ) {

iterator itr( *this, head );

return ++itr;

}

template <class Object>list<Object>::const_iterator list<Object>::begin( ) const {

const_iterator itr( *this, head );

return ++itr;

}

// Return iterator representing endmarker of list.

template <class Object>list<Object>::iterator list<Object>::end( ) {return iterator(*this, tail );}

template <class Object>

list<Object>::const_iterator list<Object>::end( ) const {

return const_iterator( *this, tail );

}

 Implémentation de la classe "list" de la STL

Page 165: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 165/238

Mar 16, 2009 F.KHOUKHI 165

// Return number of elements currently in the list.

template <class Object>

int list<Object>::size( ) const {return theSize;}

// Return true if the list is empty, false otherwise.

template <class Object>

bool list<Object>::empty( ) const {return size( ) == 0;}

// front, back, push_front, push_back, pop_front, and pop_back

// are the basic double-ended queue operations.

template <class Object>

Object & list<Object>::front( ) {return *begin( );}

template <class Object>

const Object & list<Object>::front( ) const {return *begin( );}

template <class Object>

Object & list<Object>::back( ) {return *--end( );}

 Implémentation de la classe "list" de la STL

Page 166: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 166/238

Mar 16, 2009 F.KHOUKHI 166

template <class Object>

const Object & list<Object>::back( ) const {return *--end( );}

template <class Object>

void list<Object>::push_front( const Object & x ) {insert( begin( ), x );}

template <class Object>void list<Object>::push_back( const Object & x ){insert( end( ), x );}

template <class Object>

void list<Object>::pop_front( ) {erase( begin( ) );}

template <class Object>

void list<Object>::pop_back( ) {erase( --end( ) );}

 Implémentation de la classe "list" de la STL

Page 167: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 167/238

Mar 16, 2009 F.KHOUKHI 167

// Insert x before itr.

template <class Object>

list<Object>::iterator list<Object>::insert( iterator itr, const Object & x ) {

itr.assertIsValid( );

if( itr.head != head )

throw IteratorMismatchException( "insert iterator not in this list" );

node *p = itr.current;

p->prev->next = new node( x, p->prev, p );p->prev = p->prev->next;

theSize++;

return iterator( *this, p->prev );

}

 Implémentation de la classe "list" de la STL

Page 168: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 168/238

Mar 16, 2009 F.KHOUKHI 168

// Erase item at itr.

template <class Object>

list<Object>::iterator list<Object>::erase( iterator itr )

{

itr.assertIsValid( );

if( itr == end( ) )

throw IteratorOutOfBoundsException( "cannot erase at end( )" );

if( itr.head != head )

throw IteratorMismatchException( "erase iterator not in this list" );

node *p = itr.current;

iterator retVal( *this, p->next );

p->prev->next = p->next;

p->next->prev = p->prev;

delete p;

theSize--;

return retVal;

}

 Implémentation de la classe "list" de la STL

Page 169: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 169/238

Mar 16, 2009 F.KHOUKHI 169

template <class Object>

list<Object>::iterator list<Object>::erase( iterator from, iterator to )

{

for( iterator itr = from; itr != to; )

itr = erase( itr );

return to;

}

// Public constructor for const_iterator.

template <class Object>

ConstListItr<Object>::ConstListItr( ) : head( NULL ), current( NULL )

{

}

 Implémentation de la classe "list" de la STLChapitre 17.5

Page 170: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 170/238

Mar 16, 2009 F.KHOUKHI 170

// Throws an exception if this iterator is obviously

// uninitialized. Otherwise, returns safely.

template <class Object>

void ConstListItr<Object>::assertIsInitialized( ) const

{

if( head == NULL || current == NULL )

throw IteratorUninitializedException( "list iterator" );

}

// Throws an exception if the current position is

// not somewhere in the range from begin to end, inclusive.

// Otherwise, returns safely.

template <class Object>

void ConstListItr<Object>::assertIsValid( ) const{

assertIsInitialized( );

if( current == head )

throw IteratorOutOfBoundsException( "At position prior to begin( ) inlist" );

}

 Implémentation de la classe "list" de la STLChapitre 17.5

Page 171: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 171/238

Mar 16, 2009 F.KHOUKHI 171

// Protected helper in const_iterator that returns the object

// stored at the current position. Can be called by all

// three versions of operator* without any type conversions.

template <class Object>

Object & ConstListItr<Object>::retrieve( ) const

{

assertIsValid( );

if( current->next == NULL )

throw IteratorOutOfBoundsException( "Cannot perform *end( ) in list" );

return current->data;

}

// Return the object stored at the current position.// For const_iterator, this is an accessor with a

// const reference return type.

template <class Object>

const Object & ConstListItr<Object>::operator* ( ) const

{

return retrieve( );

}

 Implémentation de la classe "list" de la STLChapitre 17.5

Page 172: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 172/238

Mar 16, 2009 F.KHOUKHI 172

// Throws an exception if operator++ cannot be safely applied

// to the current position. Otherwise, returns safely.

template <class Object>

void ConstListItr<Object>::assertCanAdvance( ) const

{

assertIsInitialized( );

if( current->next == NULL )

throw IteratorOutOfBoundsException( "Cannot perform ++end( ) in list" );

}

// Throws an exception if operator-- cannot be safely applied

// to the current position. Otherwise, returns safely.

template <class Object>void ConstListItr<Object>::assertCanRetreat( ) const

{

assertIsValid( );

if( current->prev == head )

throw IteratorOutOfBoundsException( "Cannot perform --begin( ) inlist" );

}

 Implémentation de la classe "list" de la STLChapitre 17.5

j

Page 173: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 173/238

Mar 16, 2009 F.KHOUKHI 173

template <class Object>

ConstListItr<Object> & ConstListItr<Object>::operator++ ( )

{

assertCanAdvance( );

current = current->next;

return *this;

}

template <class Object>

ConstListItr<Object> ConstListItr<Object>::operator++ ( int )

{

ConstListItr<Object> old = *this;

++( *this );

return old;

}

 Implémentation de la classe "list" de la STLChapitre 17.5

t l t l Obj t

Page 174: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 174/238

Mar 16, 2009 F.KHOUKHI 174

template <class Object>

ConstListItr<Object> & ConstListItr<Object>::operator-- ( ) {

assertCanRetreat( );

current = current->prev;

return *this;

}

template <class Object>

ConstListItr<Object> ConstListItr<Object>::operator-- ( int ) {

ConstListItr<Object> old = *this;

--( *this );

return old;

}

template <class Object>

bool ConstListItr<Object>::operator== ( const ConstListItr & rhs ) const {

return current == rhs.current;

}

 Implémentation de la classe "list" de la STLChapitre 17.5

t l t < l Obj t>

Page 175: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 175/238

Mar 16, 2009 F.KHOUKHI 175

template <class Object>

bool ConstListItr<Object>::operator!= ( const ConstListItr & rhs ) const {

return !( *this == rhs );

}

// Protected constructor for const_iterator.

// Expects the list that owns the iterator and a

// pointer that represents the current position.

template <class Object>

ConstListItr<Object>::ConstListItr( const list<Object> & source, node *p )

: head( source.head ), current( p ) {}

// Public constructor for iterator.

// Calls the base-class constructor.// Must be provided because the private constructor

// is written; otherwise zero-parameter constructor

// would be disabled.

template <class Object>

ListItr<Object>::ListItr( ) {}

 Implémentation de la classe "list" de la STLChapitre 17.5

// R t th bj t t d t th t iti

Page 176: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 176/238

Mar 16, 2009 F.KHOUKHI 176

// Return the object stored at the current position.

// For iterator, there is an accessor with a

// const reference return type and a mutator with

// a reference return type. The accessor is shown first.

template <class Object>

const Object & ListItr<Object>::operator* ( ) const {

return ConstListItr<Object>::operator*( );

}

template <class Object>

Object & ListItr<Object>::operator* ( ) {

return retrieve( );

}

template <class Object>

ListItr<Object> & ListItr<Object>::operator++ ( ) {

assertCanAdvance( );

current = current->next;

return *this;

}

 Implémentation de la classe "list" de la STLChapitre 17.5

template <class Object>

Page 177: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 177/238

Mar 16, 2009 F.KHOUKHI 177

template <class Object>

ListItr<Object> & ListItr<Object>::operator++ ( ) {

assertCanAdvance( );

current = current->next;

return *this;

}

template <class Object>

ListItr<Object> ListItr<Object>::operator++ ( int ) {

ListItr<Object> old = *this;

++( *this );

return old;

}

template <class Object>

ListItr<Object> & ListItr<Object>::operator-- ( ) {

assertCanRetreat( );

current = current->prev;

return *this;

}

 Implémentation de la classe "list" de la STLChapitre 17.5

template <class Object>

Page 178: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 178/238

Mar 16, 2009 F.KHOUKHI 178

template <class Object>

ListItr<Object> ListItr<Object>::operator-- ( int )

{

ListItr<Object> old = *this;

--( *this );

return old;

}

// Protected constructor for iterator.

// Expects the list that owns the iterator and a

// pointer that represents the current position.

template <class Object>

ListItr<Object>::ListItr( const list<Object> & source, node *p )

: ConstListItr<Object>( source, p )

{}

Être sûr de comprendre!!!

UNIVERSITE HASSAN II

FST MOHAMMADIA

DEPARTEMENT INFORMATIQUE

Page 179: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 179/238

Mar 16, 2009 F.KHOUKHI 179

CHAPITRE 4LES FONCTIONS

F.KHOUKHI

Q

INTRODUCTION• Comme dans la plupart des langages, on peuten C découper un programme en plusieurs

Page 180: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 180/238

Mar 16, 2009 F.KHOUKHI 180

en C découper un programme en plusieurs

fonctions.• Une seule de ces fonctions existeobligatoirement ; c'est la fonction principale appeléemain.

• Cette fonction principale peut, éventuellement,appeler une ou plusieurs fonctions secondaires.

De même, chaque fonction secondaire peut appeler d'autres fonctions secondaires ou s'appeler elle-même (dans ce dernier cas, on dit que la fonctionest récursive).

4.1 Définition d'une fonction• La définition d'une fonction est la donnée du

Page 181: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 181/238

Mar 16, 2009 F.KHOUKHI 181

texte de son algorithme, qu'on appelle corpsde la fonction.•Elle est de la forme/

 type nom-fonction (type-1 arg-1,...,type-n arg-n){

[déclarations de variables locales ]

liste d'instructions}

4.1 Définition d'une fonctionLe corps de la fonction débute

é t ll t d dé l ti d

Page 182: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 182/238

Mar 16, 2009 F.KHOUKHI 182

éventuellement par des déclarations devariables, qui sont locales à cette fonction.Il se termine par l'instruction de retour à lafonction appelante, return, dont la syntaxe est

return(expression);La valeur de expression est la valeur queretourne la fonction. Son type doit être le

même que celui qui a été spécifié dans l'en-tête de la fonction. Si la fonction ne retournepas de valeur (fonction de type void), sadéfinition s'achève par return;

4.1 Exemples de fonctionint produit (int a, int b){ return(a*b); }

Page 183: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 183/238

Mar 16, 2009 F.KHOUKHI 183

{ return(a*b); }

 int puissance (int a, int n){ if (n == 0) return(1);return(a * puissance(a, n-1));

}void imprime_tab (int *tab, int nb_elements){ int i;for (i = 0; i < nb_elements; i++)

printf("%d \t",tab[i]); printf("\n");return;}

4.2 Appel d'une fonctionL'appel d'une fonction se fait par l'expression:

nom fonction(para 1 para 2 para n)

Page 184: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 184/238

Mar 16, 2009 F.KHOUKHI 184

 nom-fonction( para-1, para-2 ,..., para-n)

L'ordre et le type des paramètres effectifs de la fonctiondoivent concorder avec ceux donnés dans l'en-tête de lafonction.Les paramètres effectifs peuvent être des expressions.

La virgule qui sépare deux paramètres effectifs est un simplesigne de ponctuation ;il ne s'agit pas de l'opérateur  virgule. Cela implique enparticulier que l'ordre d'évaluation des paramètres effectifsn'est pas assuré et dépend du compilateur.

Il est donc déconseillé, pour une fonction à plusieursparamètres, de faire figurer des opérateurs d'incrémentationou de décrémentation (++ ou --) dans les expressionsdéfinissant les paramètres effectifs

4.3 Déclaration d'une fonctionLe C n'autorise pas les fonctions imbriquées. La définition

d'une fonction secondaire doit donc être placée soit avant,

Page 185: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 185/238

Mar 16, 2009 F.KHOUKHI 185

p ,soit après la fonction principale main.

Toutefois, il est indispensable que le compilateur ``connaisse'' la fonction au moment où celle-ci est appelée.

Si une fonction est définie après son premier appel (enparticulier si sa définition est placée après la fonction main),elle doit impérativement être déclarée au préalable.

Une fonction secondaire est déclarée par son prototype, qui

donne le type de la fonction et celui de ses paramètres, sousla forme :type nom-fonction(type-1,...,type-n);

4.3 Déclaration d'une fonctionLes fonctions secondaires peuvent être déclarées

indifféremment avant ou au début de la fonction

Page 186: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 186/238

Mar 16, 2009 F.KHOUKHI 186

indifféremment avant ou au début de la fonction

main.Par exemple, on écrira :

int puissance (int, int );

int puissance (int a, int n){ if (n == 0) return(1);return(a * puissance(a, n-1));}

main() { int a = 2, b = 5;printf("%d\n", puissance(a,b));}

4.4 Durée de vie des variablesLes variables manipulées dans un

C t t t t ité d

Page 187: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 187/238

Mar 16, 2009 F.KHOUKHI 187

programme C ne sont pas toutes traitées dela même manière.En particulier, elles n'ont pas toutes la mêmedurée de vie.

On distingue deux catégories de variables:•  Les variables permanentes (oustatiques)

• Les variables temporaires•

4.4 Durée de vie des variablesLes variables permanentes (ou statiques)Une variable permanente occupe un emplacement en

Page 188: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 188/238

Mar 16, 2009 F.KHOUKHI 188

Une variable permanente occupe un emplacement en

mémoire qui reste le même durant toute l'exécution duprogramme.Cet emplacement est alloué une fois pour toutes lors de la

compilation.La partie de la mémoire contenant les variables

permanentes est appelée segment de données.Par défaut, les variables permanentes sont initialisées à zéropar le compilateur. Elles sont caractérisées par le mot-clef static.

• Les variables temporaires•

4.4 Durée de vie des variablesLes variables temporairesLes variables temporaires se voient allouer un emplacement

Page 189: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 189/238

Mar 16, 2009 F.KHOUKHI 189

Les variables temporaires se voient allouer un emplacement

en mémoire de façon dynamique lors de l'exécution duprogramme. Elles ne sont pas initialisées par défaut.Leur emplacement en mémoire est libéré par exemple à la

fin de l'exécution d'une fonction secondaire.

Par défaut, les variables temporaires sont situées dans lapartie de la mémoire appelée segment de pile.Dans ce cas, la variable est dite automatique.Le spécificateur de type correspondant, auto, est rarement

utilisé puisqu'il ne s'applique qu'aux variables temporaires

qui sont automatiques par défaut.La durée de vie des variables est liée à leur  portée, c'est-à-dire à la portion du programme dans laquelle elles sontdéfinies.

Page 190: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 190/238

4.4.1 Variables globalesint n;void fonction();void fonction()

Page 191: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 191/238

Mar 16, 2009 F.KHOUKHI 191

void fonction()

{ n++;printf("appel numero %d\n",n);return;}

main() {int i;

for (i = 0; i < 5; i++)fonction();}

La variable n est initialisée à zéro par le compilateur et il s'agit d'une variablepermanente.En effet, le programme affiche

appel numero 1appel numero 2appel numero 3appel numero 4appel numero 5

4.4.2 Variables locales On appelle variable locale une variable

Page 192: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 192/238

Mar 16, 2009 F.KHOUKHI 192

déclarée à l'intérieur d'une fonction (ou d'unbloc d'instructions) du programme.

Par défaut, les variables locales sonttemporaires.

Quand une fonction est appelée, elle placeses variables locales dans la pile.

A la sortie de la fonction, les variables localessont dépilées et donc perdues.

4.4.2 Variables locales Les variables locales n'ont en particulier aucun lien avec des variablesglobales de même nom.Par exemple le programme suivant:

Page 193: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 193/238

Mar 16, 2009 F.KHOUKHI 193

Par exemple, le programme suivant:

int n = 10;void fonction();void fonction(){ int n = 0;n++;

printf("appel numero %d\n",n);return;}

main()

{ int i;for (i = 0; i < 5; i++)fonction();}

affiche

appel numero 1

appel numero 1appel numero 1

appel numero 1

appel numero 1

4.4.2 Variables locales Il est toutefois possible de créer une variable localede classe statique en faisant précéder sa

Page 194: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 194/238

Mar 16, 2009 F.KHOUKHI 194

de classe statique en faisant précéder sa

déclaration du mot-clef static :static type nom-de-variable;

Une telle variable reste locale à la fonction danslaquelle elle est déclarée, mais sa valeur estconservée d'un appel au suivant.

Elle est également initialisée à zéro à lacompilation.

Par exemple, dans le programme suivant, n estune variable locale à la fonction secondairefonction, mais de classe statique.

affiche

appel numero 1

appel numero 1appel numero 1

appel numero 1

appel numero 1

4.4.2 Variables locales int n = 10; void fonction();void fonction(){ static int n;

Page 195: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 195/238

Mar 16, 2009 F.KHOUKHI 195

{ static int n;

n++;printf("appel numero %d\n",n);return;}main()

{ int i;

for (i = 0; i < 5; i++)fonction();}Ce programme affiche appel numero 1 appel numero 2 appel numero 3 appel

numero 4 appel numero 5On voit que la variable locale n est de classe statique (elle est initialisée à zéro,

et sa valeur est conservée d'un appel à l'autre de la fonction). Par contre, il s'agitbien d'une variable locale, qui n'a aucun lien avec la variable globale du mêmenom.

affiche

appel numero 1

appel numero 1appel numero 1

appel numero 1

appel numero 1

Page 196: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 196/238

4.5 Transmission des paramètres d'une fonction Exemple Transmission par valeur void echange (int, int );void echange (int a int b)

Page 197: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 197/238

Mar 16, 2009 F.KHOUKHI 197

void echange (int a, int b)

{ int t;printf("debut fonction :\n a = %d \t b = %d\n",a,b);t = a; a = b; b = t;printf("fin fonction :\n a = %d \t b = %d\n",a,b); return;}main()

{ int a = 2, b = 5;printf("debut programme principal :\n a = %d \t b = %d\n",a,b);

echange(a,b);printf("fin programme principal :\n a = %d \t b = %d\n",a,b);

}imprime

debut programme principal : a = 2 b = 5debut fonction : a = 2 b = 5fin fonction : a = 5 b = 2fin programme principal : a = 2 b = 5

4.5 Transmission des paramètres d'une fonction Pour qu'une fonction modifie la valeur d'un

Page 198: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 198/238

Mar 16, 2009 F.KHOUKHI 198

de ses arguments, il faut qu'elle ait pour paramètre l'adresse de cet objet et non savaleur.

Par exemple, pour échanger les valeurs dedeux variables, il faut écrire :

void echange (int *, int *);

4.5 Transmission des paramètres d'une fonction Exemple de transmission par adresse:void echange (int *adr_a, int *adr_b)

Page 199: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 199/238

Mar 16, 2009 F.KHOUKHI 199

{ int t; t = *adr_a;*adr_a = *adr_b;*adr_b = t;return;

}main()

{ int a = 2, b = 5;printf("debut programme principal :\n a = %d \t b =

%d\n",a,b);

echange(&a,&b);printf("fin programme principal :\n a = %d \t b = %d\n",a,b);}

4.5 Transmission des paramètres d'une fonction Rappelons qu'un tableau est un pointeur (sur 

Page 200: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 200/238

Mar 16, 2009 F.KHOUKHI 200

le premier élément du tableau).Lorsqu'un tableau est transmis commeparamètre à une fonction secondaire, seséléments sont donc modifiés par la fonction.Par exemple, le programme

4.5 Transmission des paramètres d'une fonction #include <stdlib.h>void init (int *, int );void init (int *tab int n)

Page 201: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 201/238

Mar 16, 2009 F.KHOUKHI 201

void init (int *tab, int n)

{for (int i = 0; i < n; i++)tab[i] = i;return;}

main(){ int i, n = 5;int *tab;tab = (int*)malloc(n * sizeof(int));init(tab,n);

}initialise les éléments du tableau tab.

4.6 Les qualificateurs de type const et volatile

Une variable dont le type est qualifié par  const nepeut pas être modifiée Ce qualificateur est utilisé

Page 202: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 202/238

Mar 16, 2009 F.KHOUKHI 202

peut pas être modifiée. Ce qualificateur est utilisé

pour se protéger d'une erreur de programmation. Onl'emploie principalement pour qualifier le type desparamètres d'une fonction afin d'éviter de les

modifier involontairement.Une variable dont le type est qualifié par volatile nepeut pas être impliquée dans les optimisationseffectuées par le compilateur. On utilise ce

qualificateur pour les variables susceptibles d'êtremodifiées par une action extérieure au programme.const char c ; const char *p;

4.7 La fonction main La fonction principale main est une fonctioncomme les autres Nous avons jusqu'à

Page 203: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 203/238

Mar 16, 2009 F.KHOUKHI 203

comme les autres. Nous avons jusqu àprésent considéré qu'elle était de type void,ce qui est toléré par le compilateur.

Le second prototype valide de la fonctionmain est donc int main ( int argc, char *argv[]);

4.7 La fonction main Exemple:

#include <stdio.h>

Page 204: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 204/238

Mar 16, 2009 F.KHOUKHI 204

#include <stdlib.h>int main(int argc, char *argv[])

{ int a, b;if (argc != 3)

{ printf("\nErreur : nombre invalide d'arguments");printf("\nUsage: %s int int\n",argv[0]); return(EXIT_FAILURE);}a = atoi(argv[1]);

b = atoi(argv[2]);printf("\nLe produit de %d par %d vaut : %d\n", a, b, a * b);return(EXIT_SUCCESS);

}

4.8 Pointeur sur une fonction Il est parfois utile de passer une fonction commeparamètre d'une autre fonction

Page 205: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 205/238

Mar 16, 2009 F.KHOUKHI 205

paramètre d une autre fonction.

Cette procédure permet en particulier d'utiliser unemême fonction pour différents usages. Pour cela, onutilise un mécanisme de pointeur.

Un pointeur sur une fonction correspond à l'adressedu début du code de la fonction.

Un pointeur sur une fonction ayant pour prototypetype fonction(type_1,...,type_n);est de typetype (*)(type_1,...,type_n);

4.8 Pointeur sur une fonction Ainsi, une fonction operateur_binaire prenant pour paramètres deux entiers et une fonction de type int, qui prendelle-même deux entiers en paramètres sera définie par :

Page 206: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 206/238

Mar 16, 2009 F.KHOUKHI 206

elle-même deux entiers en paramètres, sera définie par :

 int operateur_binaire(int a, int b, int (*f)(int, int))Sa déclaration est donnée par int operateur_binaire(int, int,int(*)(int, int));Exemple:

Pour appeler la fonction operateur_binaire, on utiliseracomme troisième paramètre effectif l'identificateur de lafonction utilisée, par exemple, si somme est une fonction deprototype :int somme(int, int);on appelle la fonction operateur_binaire pour la fonctionsomme par l'expression :operateur_binaire(a,b,somme)Pour appeler la fonction passée en paramètre dans le corpsde la fonction operateur_binaire, on écrit (*f)(a, b). Par exemple int operateur_binaire(int a, int b, int (*f)(int, int)){ return((*f)(a,b)); }

4.8 Pointeur sur une fonction Exemple:#include <stdlib.h>#include <stdio.h>

Page 207: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 207/238

Mar 16, 2009 F.KHOUKHI 207

#include <string.h>void usage(char *);int somme(int, int);int produit(int, int);int operateur_binaire(int, int, int(*)(int, int));void usage(char *cmd)

{ printf("\nUsage: %s int [plus|fois] int\n",cmd);return;}int somme(int a, int b){ return(a + b);}

int produit(int a, int b){ return(a * b);}int operateur_binaire(int a, int b, int (*f)(int, int)){ return((*f)(a,b)); }

4.8 Pointeur sur une fonction int main(int argc, char *argv[]){ int a, b; if (argc != 4){ printf("\nErreur : nombre invalide d'arguments"); usage(argv[0]);

Page 208: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 208/238

Mar 16, 2009 F.KHOUKHI 208

{ printf( \nErreur : nombre invalide d arguments ); usage(argv[0]);

return(EXIT_FAILURE);}a = atoi(argv[1]);b = atoi(argv[3]);if (!strcmp(argv[2], "plus"))

{ printf("%d\n",operateur_binaire(a,b,somme));return(EXIT_SUCCESS);}If (!strcmp(argv[2], "fois")) {printf("%d\n",operateur_binaire(a,b,produit));return(EXIT_SUCCESS);

}else { printf("\nErreur : argument(s) invalide(s)"); usage(argv[0]);

return(EXIT_FAILURE);}

}

4.8 Pointeur sur une fonction Les pointeurs sur les fonctions sont notammentutilisés dans la fonction de tri des éléments d'un

Page 209: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 209/238

Mar 16, 2009 F.KHOUKHI 209

utilisés dans la fonction de tri des éléments d un

tableau qsort et dans la recherche d'un élémentdans un tableau bsearch.

Ces deux fonctions sont définies dans la libriarie

standard (stdlib.h).Le prototype de la fonction de tri (algorithmequicksort) est :

void qsort(void *tableau, size_t nb_elements, size_ttaille_elements, int(*comp)(const void *, const void*));

4.8 Pointeur sur une fonction Exemple:

Page 210: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 210/238

Mar 16, 2009 F.KHOUKHI 210

#include <stdlib.h>#include <stdio.h>

#include <string.h>

#define NB_ELEMENTS 10void imprime_tab1(int*, int);

void imprime_tab2(char**, int);

int comp_int(int *, int *);int comp_str(char **, char **);

4.8 Pointeur sur une fonction Exemple:void imprime_tab1(int *tab, int nb){ int i; printf("\n");

Page 211: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 211/238

Mar 16, 2009 F.KHOUKHI 211

{ int i; printf( \n );

for (i = 0; i < nb; i++)printf("%d \t",tab[i]);printf("\n"); return;}void imprime_tab2(char **tab, int nb)

{ int i; printf("\n");for (i = 0; i < nb; i++)printf("%s \t",tab[i]);printf("\n");return;

}int comp_int(int *a, int *b){ return(*a - *b); }int comp_str(char **s1, char **s2){ return(strcmp(*s1,*s2)); }

4.8 Pointeur sur une fonction Exemple: quicksortint main(){ int *tab1;

Page 212: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 212/238

Mar 16, 2009 F.KHOUKHI 212

{ int tab1;

char *tab2[NB_ELEMENTS] = {"toto", "Auto", "auto", "titi", "a", "b",\ "z", "i ,"o","d"};int i;tab1 = (int*)malloc(NB_ELEMENTS * sizeof(int));for (i = 0 ; i < NB_ELEMENTS; i++)

tab1[i] = random() % 1000;imprime_tab1(tab1, NB_ELEMENTS);qsort(tab1, NB_ELEMENTS, sizeof(int), comp_int);imprime_tab1(tab1, NB_ELEMENTS);/************************/imprime_tab2(tab2, NB_ELEMENTS);qsort(tab2, NB_ELEMENTS, sizeof(tab2[0]), comp_str);imprime_tab2(tab2, NB_ELEMENTS); return(EXIT_SUCCESS);}

Page 213: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 213/238

4.8 Pointeur sur une fonction Ainsi, le programme suivant prend enargument une chaîne de caractères et

Page 214: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 214/238

Mar 16, 2009 F.KHOUKHI 214

argument une chaîne de caractères etdétermine si elle figure dans un tableau dechaînes de caractères prédéfini, sansdifférencier minuscules et majuscules.

Rappelons que bsearch ne s'applique qu'auxtableaux triés ; il faut donc appliquer aupréalable la fonction de tri qsort.

 

4.8 Pointeur sur une fonction #include <stdlib.h>#include <stdio.h>#include <string.h>

Page 215: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 215/238

Mar 16, 2009 F.KHOUKHI 215

#include <ctype.h>#define NB_ELEMENTS 4

int comp_str_maj(char **, char **);

int comp_str_maj(char **s1, char **s2)

{ int i; char *chaine1, *chaine2;chaine1 = (char*)malloc(strlen(*s1) * sizeof(char));chaine2 = (char*)malloc(strlen(*s2) * sizeof(char));

for (i = 0; i < strlen(*s1); i++)chaine1[i] = tolower((*s1)[i]);

for (i = 0; i < strlen(*s2); i++)chaine2[i] = tolower((*s2)[i]);return(strcmp(chaine1,chaine2));

4.8 Pointeur sur une fonction int main(int argc, char *argv[]){ char *tab[NB_ELEMENTS] =

Page 216: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 216/238

Mar 16, 2009 F.KHOUKHI 216

{"TOTO", "Auto", "auto", "titi"};char **res; qsort(tab, NB_ELEMENTS,

sizeof(tab[0]), comp_str_maj);if ((res =

bsearch(&argv[1],tab,NB_ELEMENTS,sizeof(tab[0]),comp_str_maj)) ==\ NULL)printf("\nLe tableau ne contient pas l'element

%s\n",argv[1]);

else printf("\nLe tableau contient l'element %s sousla forme %s\n",argv[1], \ *res);return(EXIT_SUCCESS);}

4.9 Fonctions avec un nombre variable de paramètres Il est possible en C de définir des fonctionsqui ont un nombre variable de paramètres

Page 217: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 217/238

Mar 16, 2009 F.KHOUKHI 217

qui ont un nombre variable de paramètres.

Ainsi, une fonction ayant pour prototype :

int f(int a, char c, ...);

4.9 Fonctions avec un nombre variable de paramètres Exemple:

#include <stdlib.h>

Page 218: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 218/238

Mar 16, 2009 F.KHOUKHI 218

#include <stdio.h>#include <stdarg.h>int add(int,...);int add(int nb,...){ int res = 0;

int i; va_list liste_parametres; va_start(liste_parametres, nb);for (i = 0; i < nb; i++)res += va_arg(liste_parametres, int); va_end(liste_parametres);return(res);}

int main(void){ printf("\n %d", add(4,10,2,8,5));printf("\n %d\n", add(6,10,15,5,2,8,10));return(EXIT_SUCCESS);}

UNIVERSITE HASSAN II

FST MOHAMMADIA

DEPARTEMENT INFORMATIQUE

Page 219: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 219/238

Mar 16, 2009 F.KHOUKHI 219

CHAPITRE 5LES FICHIERS

F.KHOUKHI

INTRODUCTION• Le C offre la possibilité de lire et d'écrire des données dans un fichier.

•Pour des raisons d'efficacité, les accès à un fichier se font par 

Page 220: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 220/238

Mar 16, 2009 F.KHOUKHI 220

l'intermédiaire d'une mémoire-tampon (buffer ), ce qui permet de réduirele nombre d'accès aux périphériques (disque...).

Pour pouvoir manipuler un fichier, un programme a besoin d'un certainnombre d'informations : l'adresse de l'endroit de la mémoire-tampon oùse trouve le fichier, la position de la tête de lecture, le mode d'accès aufichier (lecture ou écriture) ...Ces informations sont rassemblées dansune structure dont le type, FILE *, est défini dans stdio.h. Un objet detype FILE * est appelé flot de données (en anglais, stream).

Remarque• Avant de lire ou d'écrire dans un fichier, onnotifie son accès par la commande fopen.

Page 221: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 221/238

Mar 16, 2009 F.KHOUKHI 221

notifie son accès par la commande fopen.Cette fonction prend comme argument lenom du fichier, négocie avec le systèmed'exploitation et initialise un flot de données,

qui sera ensuite utilisé lors de l'écriture ou dela lecture. Après les traitements, on annule laliaison entre le fichier et le flot de données

grâce à la fonction fclose.

Ouverture et fermeture d'un fichier La fonction fopen

Cette fonction, de type FILE* ouvre un fichier et lui associe un flot de données. Sa syntaxe est :fopen("nom-de-fichier ","mode")La valeur retournée par fopen est un flot de données. Si l'exécution de cette fonction ne sedéroule pas normalement la valeur retournée est le pointeur NULL Il est donc recommandé de

Page 222: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 222/238

Mar 16, 2009 F.KHOUKHI 222

déroule pas normalement, la valeur retournée est le pointeur NULL. Il est donc recommandé detoujours tester si la valeur renvoyée par la fonction fopen est égale à NULL afin de détecter leserreurs (lecture d'un fichier inexistant...).

Le premier argument de fopen est le nom du fichier concerné, fourni sous forme d'une chaîne decaractères. On préférera définir le nom du fichier par une constante symbolique au moyen de ladirective #define plutôt que d'expliciter le nom de fichier dans le corps du programme.

Le second argument, mode, est une chaîne de caractères qui spécifie le mode d'accès au

fichier. Les spécificateurs de mode d'accès diffèrent suivant le type de fichier considéré. Ondistingueles fichiers textes, pour lesquels les caractères de contrôle (retour à la ligne ...) seront interprétésen tant que tels lors de la lecture et de l'écriture ;les fichiers binaires, pour lesquels les caractères de contrôle se sont pas interprétés.Les différents modes d'accès sont les suivants :

Ouverture et fermeture d'un fichier 

Les différents modes d'accès sont les suivants :

ouverture d'un fichier texte en écriture"w"

ouverture d'un fichier texte en lecture"r"

Page 223: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 223/238

Mar 16, 2009 F.KHOUKHI 223ouverture d'un fichier binaire en lecture/écriture à la fin"a+b"

ouverture d'un fichier binaire en lecture/écriture"w+b"

ouverture d'un fichier binaire en lecture/écriture"r+b"

ouverture d'un fichier texte en lecture/écriture à la fin"a+"

ouverture d'un fichier texte en lecture/écriture"w+"

ouverture d'un fichier texte en lecture/écriture"r+"

ouverture d'un fichier binaire en écriture à la fin"ab"

ouverture d'un fichier binaire en écriture"wb"

ouverture d'un fichier binaire en lecture"rb"

ouverture d'un fichier texte en écriture à la fin"a"

ouverture d un fichier texte en écriturew

Ouverture et fermeture d'un fichier 

 Ces modes d'accès ont pour particularités :Si le mode contient la lettre r, le fichier doit

Page 224: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 224/238

Mar 16, 2009 F.KHOUKHI 224

Si le mode contient la lettre r, le fichier doitexister.Si le mode contient la lettre w, le fichier peutne pas exister. Dans ce cas, il sera créé. Si le

fichier existe déjà, son ancien contenu seraperdu.Si le mode contient la lettre a, le fichier peut

ne pas exister. Dans ce cas, il sera créé. Si lefichier existe déjà, les nouvelles donnéesseront ajoutées à la fin du fichier précédent

Ouverture et fermeture d'un fichier 

  Trois flots standard peuvent être utilisés en C sansqu'il soit nécessaire de les ouvrir ou de les fermer :

Page 225: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 225/238

Mar 16, 2009 F.KHOUKHI 225

stdin (standard input) : unité d'entrée (par défaut, leclavier) ;stdout (standard output) : unité de sortie (par défaut,l'écran) ;

stderr (standard error) : unité d'affichage desmessages d'erreur (par défaut, l'écran).Il est fortement conseillé d'afficher systématiquementles messages d'erreur sur stderr afin que ces

messages apparaissent à l'écran même lorsque lasortie standard est redirigée.

La fonction fclose 

Elle permet de fermer le flot qui a été associé

Page 226: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 226/238

Mar 16, 2009 F.KHOUKHI 226

p qà un fichier par la fonction fopen. Sa syntaxeest : fclose(flot )où flot est le flot de type FILE* retourné par la

fonction fopen correspondant.La fonction fclose retourne un entier qui vautzéro si l'opération s'est déroulée

normalement (et une valeur non nulle en casd'erreur).

Les entrées-sorties formatées 

La fonction d'écriture fprintf 

Page 227: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 227/238

Mar 16, 2009 F.KHOUKHI 227

La fonction fprintf, analogue à printf, permet d'écriredes données dans un fichier.Sa syntaxe est fprintf(flot ,"chaîne decontrôle",expression-1, ..., expression-n)

où flot est le flot de données retourné par la fonctionfopen.Les spécifications de format utilisées pour la fonctionfprintf sont les mêmes que pour printf.

Les entrées-sorties formatéesLa fonction de saisie fscanf 

La fonction fscanf, analogue à scanf, permet de

Page 228: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 228/238

Mar 16, 2009 F.KHOUKHI 228

lire des données dans un fichier.Sa syntaxe est semblable à celle de scanf :fscanf(flot ,"chaîne de contrôle",argument- 1,...,argument-n)où flot est le flot de données retourné par fopen.

Les spécifications de format sont ici les mêmesque celles de la fonction scanf.

Impression et lecture de caractères

Similaires aux fonctions getchar et putchar, les fonctions fgetc etfputc permettent respectivement de lire et d'écrire un caractère

Page 229: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 229/238

Mar 16, 2009 F.KHOUKHI 229

dans un fichier.La fonction fgetc, de type int, retourne le caractère lu dans lefichier. Elle retourne la constante EOF lorsqu'elle détecte la fin dufichier. Son prototype est int fgetc(FILE* flot );où flot est le flot de type FILE* retourné par la fonction fopen.Comme pour la fonction getchar, il est conseillé de déclarer de

type int la variable destinée à recevoir la valeur de retour de fgetcpour pouvoir détecter correctement la fin de fichier.

Impression et lecture de caractères

La fonction fputc écrit caractere dans le flot dedonnées :

Page 230: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 230/238

Mar 16, 2009 F.KHOUKHI 230

int fputc(int caractere, FILE *flot)Elle retourne l'entier correspondant au caractère lu(ou la constante EOF en cas d'erreur).

Il existe également deux versions optimisées desfonctions fgetc et fputc qui sont implémentées par desmacros. Il s'agit respectivement de getc et putc. Leur syntaxe est similaire à celle de fgetc et fputc : int

getc(FILE* flot );int putc(int caractere, FILE *flot )

Impression et lecture de caractèresAinsi, le programme suivant lit le contenu du fichier texte entree, et le recopie caractère par caractère dans le fichier sortie :#include <stdio.h>#include <stdlib.h>#define ENTREE "entree.txt"#define SORTIE "sortie.txt"

Page 231: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 231/238

Mar 16, 2009 F.KHOUKHI 231

int main(void){

FILE *f_in, *f_out;int c;

 if ((f_in = fopen(ENTREE,"r")) == NULL)

{fprintf(stderr, "\nErreur: Impossible de lire le fichier %s\n",ENTREE);return(EXIT_FAILURE);

}if ((f_out = fopen(SORTIE,"w")) == NULL){

fprintf(stderr, "\nErreur: Impossible d'ecrire dans le fichier %s\n", \SORTIE);

return(EXIT_FAILURE);}

while ((c = fgetc(f_in)) != EOF)fputc(c, f_out);

fclose(f_in);

fclose(f_out);return(EXIT_SUCCESS);

}

Relecture d'un caractèreIl est possible de replacer un caractère dans un flot au moyen de la fonction ungetc :int ungetc(int caractere, FILE *flot);Cette fonction place le caractère caractere (converti en unsigned char) dans le flot flot. En particulier, si caractere est égal au dernier caractère lu dans le flot, elle annule le déplacement provoqué par la lecture précédente. Toutefois, ungetc peut être utilisée avecn'importe quel caractère (sauf EOF). Par exemple, l'exécution du programme suivant#include <stdio.h>

Page 232: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 232/238

Mar 16, 2009 F.KHOUKHI 232

#include <stdlib.h>#define ENTREE "entree.txt"

int main(void){

FILE *f_in;int c;

 if ((f_in = fopen(ENTREE,"r")) == NULL)

{

fprintf(stderr, "\nErreur: Impossible de lire le fichier %s\n",ENTREE);return(EXIT_FAILURE);

while ((c = fgetc(f_in)) != EOF){

if (c == '0')ungetc('.',f_in);

putchar(c);

}fclose(f_in);return(EXIT_SUCCESS);

}sur le fichier entree.txt dont le contenu est 097023 affiche à l'écran 0.970.23

Les entrées-sorties binaires Les fonctions d'entrées-sorties binaires permettent de transférer des données dans un fichier sans transcodage. Elles sont donc plus efficaces que les fonctions d'entrée-sortie standard, maisles fichiers produits ne sont pas portables puisque le codage des données dépend desmachines.

Page 233: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 233/238

Mar 16, 2009 F.KHOUKHI 233

Elles sont notamment utiles pour manipuler des données de grande taille ou ayant un typecomposé. Leurs prototypes sont :size_t fread(void *pointeur, size_t taille, size_t nombre, FILE *flot);size_t fwrite(void *pointeur, size_t taille, size_t nombre, FILE *flot);où pointeur est l'adresse du début des données à transférer,taille la taille des objets à transférer, nombre leur nombre.

Rappelons que le type size_t, défini dans stddef.h, correspond au type du résultat de l'évaluation

de sizeof. Il s'agit du plus grand type entier non signé.La fonction fread lit les données sur le flot flot et lafonction fwrite les écrit. Elles retournent toutes deux lenombre de données transférées.

Page 234: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 234/238

Mar 16, 2009 F.KHOUKHI 234

Exemplele programme suivant écrit un tableau d'entiers(contenant les 50 premiers entiers) avec fwrite dans

le fichier sortie, puis lit ce fichier avec fread et imprime les élémentsdu tableau.

Exemple #include <stdio.h>#include <stdlib.h>#define NB 50#define F_SORTIE "sortie"int main(void){ FILE *f in, *f out; int *tab1, *tab2; int i;

Page 235: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 235/238

Mar 16, 2009 F.KHOUKHI 235

{ _ , _ ; , ; ;

tab1 = (int*)malloc(NB * sizeof(int));tab2 = (int*)malloc(NB * sizeof(int));for (i = 0 ; i < NB; i++) tab1[i] = i; /* ecriture du tableau dans F_SORTIE */if ((f_out = fopen(F_SORTIE, "w")) == NULL){ fprintf(stderr, "\nImpossible d'ecrire dans le fichier %s\n",F_SORTIE); return(EXIT_FAILURE); }fwrite(tab1, NB * sizeof(int), 1, f_out);fclose(f_out); /* lecture dans F_SORTIE */if ((f_in = fopen(F_SORTIE, "r")) == NULL)

{ fprintf(stderr, "\nImpossible de lire dans le fichier %s\n",F_SORTIE);

return(EXIT_FAILURE);}fread(tab2, NB * sizeof(int), 1, f_in);fclose(f_in); for (i = 0 ; i < NB; i++)printf("%d\t",tab2[i]); printf("\n");return(EXIT_SUCCESS);} Les éléments du tableau sont bien affichés à l'écran. Par contre, on constate que le contenu du fichier  sortie n'est pas encodé.

Positionnement dans un fichier 

Les différentes fonctions d'entrées-sorties permettent d'accéder à unfichier en mode séquentiel : les données du fichier sont lues ou écritesles unes à la suite des autres. Il est également possible d'accéder à unfichier en mode direct , c'est-à-dire que l'on peut se positionner à

Page 236: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 236/238

Mar 16, 2009 F.KHOUKHI 236

n'importe quel endroit du fichier. La fonction fseek permet de sepositionner à un endroit précis ; elle a pour prototype : int fseek(FILE*flot , long deplacement , int origine);La variable deplacement détermine la nouvelle position dans le fichier. Ils'agit d'un déplacement relatif par rapport à l'origine ; il est compté ennombre d'octets. La variable origine peut prendre trois valeurs :

SEEK_SET (égale à 0) : début du fichier ;SEEK_CUR (égale à 1) : position courante ;SEEK_END (égale à 2) : fin du fichier.

Positionnement dans un fichier 

La fonction int rewind(FILE *flot );

Page 237: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 237/238

Mar 16, 2009 F.KHOUKHI 237

permet de se positionner au débutdu fichier. Elle est équivalente àfseek(flot , 0, SEEK_SET);

La fonction long ftell(FILE *flot );retourne la position courante dans lefichier (en nombre d'octets depuisl'origine).

Exemple #include <stdio.h>#include <stdlib.h>#define NB 50#define F_SORTIE "sortie«int main(void){ FILE *f_in, *f_out; int *tab; int i;tab = (int*)malloc(NB * sizeof(int));

Page 238: cour de C

8/14/2019 cour de C

http://slidepdf.com/reader/full/cour-de-c 238/238

for (i = 0 ; i < NB; i++) tab[i] = i; /* ecriture du tableau dans F_SORTIE */if ((f_out = fopen(F_SORTIE, "w")) == NULL)

{ fprintf(stderr, "\nImpossible d'ecrire dans le fichier %s\n",F_SORTIE);return(EXIT_FAILURE);

}fwrite(tab, NB * sizeof(int), 1, f_out);fclose(f_out); /* lecture dans F_SORTIE */if ((f_in = fopen(F_SORTIE, "r")) == NULL)

{ fprintf(stderr, "\nImpossible de lire dans le fichier %s\n",F_SORTIE);return(EXIT_FAILURE);} /* on se positionne a la fin du fichier */

fseek(f_in, 0, SEEK_END);printf("\n position %ld", ftell(f_in)); /* deplacement de 10 int en arriere */fseek(f_in, -10 * sizeof(int), SEEK_END);