IDRIS - CNRS Cours IDRIS : langage C
Support de cours

20 janvier 1998 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Patrick Corde
Version PostScript disponible

Document ralis partir des transparents du cours "Langage C" de l'IDRIS.
Pour une impression correcte, utilisez la version PostScript.
TOC cours IDRIS F90


.

1 - Prsentation du langage C

Retour dbut .

1.1 - Historique

Langage de programmation dvelopp en 1970 par Dennie Ritchie aux Laboratoires Bell d'AT&T. Il est l'aboutissement de deux langages :

Il fut limit l'usage interne de Bell jusqu'en 1978 date laquelle Brian Kernighan et Dennie Ritchie publirent les spcifications dfinitives du langage : << The C programming Language >>.

Au milieu des annes 1980 la popularit du langage tait tablie. De nombreux compilateurs ont t crits, mais comportant quelques incompatibilits portant atteinte l'objectif de portabilit. Il s'est ensuivi un travail de normalisation effectu par le comit de normalisation X3J11 de l'ANSI qui a abouti en 1988 avec la parution par la suite du manuel : << The C programming Language - 2me dition >>.

Retour dbut .

1.2 - Intrts du langage

Retour dbut .

1.3 - Qualits attendues d'un programme

Retour dbut


.

2 - Gnralits

Retour dbut .

2.1 - Jeu de caractres

Retour dbut .

2.2 - Identificateurs et mots-cls

Exemples

Retour dbut .

2.3 - Structure d'un programme C

Exemple :

#include 
#define  PI 3.14159
/*  calcul de la surface d'un cercle */
main()
{
  float rayon, surface;
  float calcul(float rayon);

  printf("Rayon = ? ");
  scanf("%f", &rayon);
  surface = calcul(rayon);
  printf("Surface = %f\n", surface);
}
/* dfinition de fonction */
float calcul(float r)
{
/* dfinition de la variable locale */
  float a;

  a = PI * r * r;
  return(a);
}

Retour dbut .

2.4 - Compilation et dition des liens

Le source d'une application crite en langage C peut tre stock dans un ou plusieurs fichiers dont le suffixe est << .c >>
La compilation de ce source s'effectue l'aide de la commande cc. Sans autre spcification, cette commande enchane 3 tapes :
  1. appel au pr-processeur (cpp),
  2. appel au compilateur,
  3. appel l'diteur de liens.

Cette commande admet plusieurs options telles :

Retour dbut


.

3 - Les dclarations

Retour dbut .

3.1 - Les types de base

Le langage contient des types de base qui sont les entiers, les rels simple et double prcision et les caractres que l'on identifie l'aide des mots-cls int, float, double et char respectivement.

De plus il existe un type ensemble vide : le type void.

Les mots-cls short et long permettent d'influer sur la taille mmoire des entiers et des rels.


Liste des diffrents types de base


SyntaxeType
voidensemble vide
charcaractre
short intentier court
intentier par dfaut
long intentier long
floatrel simple prcision
doublerel double prcision
long doublerel prcision tendue

Remarques

Les deux mots-cls unsigned et signed peuvent s'appliquer aux types caractre et entier pour indiquer si le bit de poids fort doit tre considr ou non comme un bit de signe. Les entiers sont signs par dfaut, tandis que les caractres peuvent l'tre ou pas suivant le compilateur utilis.
Une dclaration telle que unsigned char permettra de dsigner une quantit comprise entre 0 et 255, tandis que signed char dsignera une quantit comprise entre -128 et +127.
De mme unsigned long permettra de dsigner une quantit comprise entre 0 et 232-1, et long une quantit comprise entre -231 et 231-1.

Exemple

#include <stdio.h>
unsigned char mask;
long          val;
main()
{
  unsigned int indice;
  float        x;
  double       y;
  char         c;
        ...
  return;
}
double f(double x)
{
  unsigned short taille;
  int            i;
  unsigned long  temps;
  double         y;
       ...
  return y;
}

Retour dbut .

3.2 - Les numrations de constantes

Les numrations sont des types dfinissant un ensemble de constantes qui portent un nom que l'on appelle numrateur. Elles servent rajouter du sens de simples numros, dfinir des variables qui ne peuvent prendre leur valeur que dans un ensemble fini de valeurs possibles identifies par un nom symbolique.

Syntaxe

enum [nom] {
   numrateur1,
   numrateur2,
   numrateur3,
       ...
   numrateurn
};

Les constantes figurant dans les numrations ont une valeur entire affecte de faon automatique par le compilateur en partant de 0 par dfaut et avec une progression de 1. Les valeurs initiales peuvent tre forces lors de la dfinition.

enum couleurs {noir, bleu, vert, rouge, blanc,
               jaune};
enum couleurs {
   noir = -1,
   bleu,
   vert,
   rouge = 5,
   blanc,
   jaune
};

Dans le 1er exemple, les valeurs gnres par le compilateur seront :

noir0vert2blanc4
bleu1rouge3jaune5

et dans le 2e :

noir-1vert1blanc6
bleu0rouge5jaune7

Retour dbut .

3.3 - Les pointeurs

Un pointeur est une variable ou une constante dont la valeur est une adresse.

L'adresse d'un objet est indissociable de son type. On pourra se dfinir par exemple des pointeurs de caractres, des pointeurs d'entiers voire des pointeurs d'objets plus complexes.

L'opration fondamentale effectue sur les pointeurs est l'indirection, c'est--dire l'valuation de l'objet point. Le rsultat de cette indirection dpend du type de l'objet point.

Par exemple si p_car et p_reel sont respectivement un pointeur de caractres et un pointeur de rel simple prcision rfrenant la mme adresse µ, une indirection effectue sur p_car dsignera le caractre situ l'adresse µ, tandis qu'une indirection effectue sur p_reel dsignera le rel simple prcision situe la mme adresse.

Bien qu'ayant le mme contenu (l'adresse µ), ces deux pointeurs ne sont pas identiques !

Retour dbut .

3.4 - Forme gnrale d'une dclaration

La forme gnrale d'une dclaration est la suivante :
< type >  < construction > [,< construction >,...];

o type est un type lmentaire (type de base, numration de constantes) ou un type que l'on s'est dfini, et construction est soit un identificateur soit un objet plus complexe construit l'aide de constructeurs homognes.

Retour dbut .

3.5 - Constructeurs homognes

Des objets plus complexes peuvent tre forms l'aide des constructeurs homognes :

Symboles associs aux constructeurs homognes

SymboleObjet construit
*pointeur
[ ]vecteur
( )fonction

Exemple

   char     lignes[100];
   int     *p_entier;
   double   fonc();

Les dclarations prcdentes permettent de dfinir respectivement :

Ces constructeurs peuvent se combiner entre eux, permettant ainsi de dfinir des objets encore plus complexes.

Exemple

   char    *chaines[100];
   int      mat[100][40];
   char   **argv;
Le constructeur homogne * est moins prioritaire que les deux autres. De ce fait, les dclarations prcdentes permettent de dfinir respectivement :

L'utilisation de parenthses permet de modifier la priorit et donc l'ordre d'valuation.

Exemple

   int    (*tab)[10];
   char   (*f)();
   char   *(*g)();
   float  *(*tabf[20])();
Cet exemple permet de dfinir respectivement :

Retour dbut .

3.6 - Constructeurs htrognes

Les constructeurs htrognes permettent de dfinir des objets renfermant des entits de nature diffrente.

Il en existe 3 :

Les structures permettent de regrouper des objets dont les types peuvent tre diffrents.

Syntaxe

     struct [ nom ] {
        < liste de dclarations >
     };
     
Les objets regroups sont les membres ou composantes de la structure les contenant.

Remarques

Exemple

     struct {
         char         c;
         unsigned int i;
         float        tab[10];
         char        *p;
MMΰ
==ϟ>=
Default	 	0	@02A0GP0R0S00
?
?@Box01AA8_F@@WpH?`IPpRQKpEPZCp"A$NAgğ?n%;,^%WAißX A;BnU@
-B;U,CBJXB;-=16"oBZ<=6"oB6J6"
oB#V6"
oBF@N%p?ͶN%p¼;
N%p+EFN%p‰Aq#?TwM>TjMy,4s\/ A
pBV@BܗTBB-a-=X#oB?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box02AA89E4oBk(-oBĄ?x'oBzF@:p"oB% A5;AR=MU'=!\U@=6 A=K9npٻnp{L<np}&=npvEVToBWRToBD*?vNToBoF@:JToBx"0QAe,V9A5?WV+AAe9PA, ΩT, V@, * A, ŒRp8ػDp<9p¸&=-pMEJoBJFoB?aBoBF@&>oB'W@V̟A Ai, &=jpMe;+?>;o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@p-Torus01Ab-A
 =Jo=lI{]@=wFÓ@|=kB@N=]^>@/=,e;T`@=VL:G
= _;=S>9/v
=_Bޤ
8=~mFÂNW=fIëWv?QןCtrV PzBG_@Mx?@H¬;@BDD7|b@A5Ra@@m3ÀA5ktD7ÙH˜;]S
1M?Js PqBĮRGk/6<¤}.&b@F\+ʅ@:m(&@.$,@}8ZV"äe@"®b!Jフ8RP"Ú.˜$O:`(Wi	F+Ml=›w.ɑWB+ԾuYӀh@Ajiz@Cd	f	Wx@Å@oÂj@Ī_'þ o*ލâÐRd	Q	ÿAà_ìw|YzɎQ/2§k`..*p@+LR@:N($<@$Ò>@~;"Á’q@J!ju m;"n#=$æx?HN(ú+
ɟa.QCîRLBÞPy@B?=Md@;I@7}E¦@4kfB0\z@D30:A–4@NB7ãXEo;ňIwN?bM±'SBvP ZJEwͽ,`;iIp@rF*󽼔@fB}APY>.@Vb;i#ֽ@L:cݼ"S;]b;üХ~\Y>Ê*%^*fBèהЋrF{wY]iI?1v}CJAQB\>B"PB@j?LB]@;fHBA47DDB*@5іAB8@3ԃ@B3>5ABJy@7DB#;÷HBgv?&MBTBL.PBKDyvk/]SB<>z.7B@I+=B@!g(}/B-A$6%Bp@~S"N3Bfm@b!#Bin>S"a?Bq$!:By/g(åGB
U+QB  z.CB9p~B+C}>}VCI@d/<C@z	Ý^	CrAêCf@
ulC@$C>rCTj C	ój	CLeåFCpN}\C;yhgQ/CSX?SQ^.C@+C1@ŒH(C{	AB¹$Cd@8"Ccː@uTK!C'>>"Cd[/$C	¡T(Cos+CaaZd.CljbRCCG?P™BChɓ@kM\?Cd@I6;C`
AmE°7C@yZB4C@a:A—3CI?ZB4CZamE(7ClH?IL;CפMѮ?CP¢BC^nͽ	JCC?5̽3gICh@ɽnFC@Ľf`BC
ATkT>C?@ս_;CD@ռL:CB/?e;CO3`G-^>C}<[Ž|lBCyɽwxFC/n̽?mIC]AQBYCC?"PBBC*@BMB?C}Z@HB;C[
ADBO7C@.ABL5C"|@
@B3CzM?ABV	5CmaSDB7CRHB/;CMB?Cg"PBBC|^SBk/C#?>Bx.C9ڑ@GBi+C|@;Bra(Cq	A/B$C@9BP"C@#B/c!C=>9BV"Cd/B$Cg;Bm(CƂGB+Cfu=B&~.C[bTCBC<1>ZCK{CMڎ@AC!`C@d	Cԁ	CAC&C@oCfC@HCCs->oCqCĈjCC#d	C	CgACjCjYCVC5h
R/C5Bq>a.CB@n+C
B.@N(CBA($CyB8P@<"CqBM@K!CpvBs><"CBq$CBߡN(CB+b+CBAa.C4Bc~p"CC	RB>>׆BC|PBj@ҩ?CkMB8@|;CΊIBA%7CZEB@4CIPBB3@3C74CqhBBo;z7CEBDn;C IBƩ?CCMBІBCPBŐy@JC=4OtjIC@=܍@ysFC=m@fBCS=AY>Cd:=n@b;C=<@
M:Cl=b;Cg3=Y>C=fBC=msFC9=XljICC=
CCA?Q1BCD,Pey@?C$M¸@_;CHw@7CD„@5CAz@"3Cˁ@K5CɔAe(7C>D“Q;C]H?CL]M*BCP]k/CWRT{.CB›Zp@+CP„0@g(CF@$C9ڑ@T"C\>ɫq@Zc!C"uhT"CG2]|$C0$=`g(Cw.b%+C;‘M{.C6™CCYվz~CX\h@eC#F^@	C0j	S]@C@Cqouj@CûľCk3~C)
	C^	A|eC;@s~CLVkBXQ/AeBc.Ïb@şB+Hr@BT(@`B$@BZ>"d@vBJ!1𾦌BP8"GB6$B	H(r	Bz+XB].ßݑ	RBiCPB B^@MBP?@GIB;9@oEB7X@\BBg4C{a@i=12>2?>23?3@?34@4A@45A5BA56B6CB67C7DC78D8ED89E9FE9:F:GF:;G;<G;0<<IH<=I=JI=>J>KJ>?K?LK?@L@ML@AMANMABNBONBCOCPOCDPDQPDEQERQEFRFSRFGSGHSG<HHUTHIUIVUIJVJWVJKWKXWKLXLYXLMYMZYMNZN[ZNO[O\[OP\P]\PQ]Q^]QR^R_^RS_ST_SHTTa`TUaUbaUVbVcbVWcWdcWXdXedXYeYfeYZfZgfZ[g[hg[\h\ih\]i]ji]^j^kj^_k_`k_T``ml`amanmabnbonbcocpocdpdqpdeqerqefrfsrfgsgtsghthuthiuivuijvjwvjkwklwk`llyxlmymzymnzn{zno{o|{op|p}|pq}q~}qr~r~rssstttuuuvvvwwxwlxxxyyyzzz{{{|||}}}~~~x		
	




			





		
	

0ADefault@	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~	

 !"#$%&'()*+,-./0123456789:;<=>?PA	@Box03AA8_BBṔAC=AAD=&犁A$/F=mB³iAG=dBB@"G<A6@,v<g@6<#hB˜
@@ԍAφ=yf<]B6Ɂ:^BBAh'AfmAOh
3LAgnB*Ag4dBB0@8Aa@@!•hB@½iBB$IA|蒁XcBuEoBBP[ZAŀׇ„]B(^BB
A	,AA,rUˁAl,mB"A,IhBP@,bB牬-8]BɈj-?g-A`F-oBB-%2-	jBB|T-dBB@y,^BB+NAksA,APjAimB‘AhohB	@&bB.^]BZH*''*A+koBBf,iBBZdBBt@`A6'\Ͽ~T7zT:[Ͽ?ж7)[?o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box04AA8_BBṔAC=AAD=&犁A$/F=mB³iAG=dBB@"G<A6@,v<g@6<#hB˜
@@ԍAφ=yf<]B6Ɂ:^BBAh'AfmAOh
3LAgnB*Ag4dBB0@8Aa@@!•hB@½iBB$IA|蒁XcBuEoBBP[ZAŀׇ„]B(^BB
A	,AA,rUˁAl,mB"A,IhBP@,bB牬-8]BɈj-?g-A`F-oBB-%2-	jBB|T-dBB@y,^BB+NAksA,APjAimB‘AhohB	@&bB.^]BZH*''*A+koBBf,iBBZdBBt@`A6'\Ͽ~T7zT:[Ͽ?ж7)[?o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box05AA8y,	ABD>@ȂgAuD=dȂ">{B*2BB?>,4AfE=I	0~=fiBy@BB<>
@!AXE=@/? hA4̂AIGF=ŶAcNN<0AA^-,BB%ɂF)AVhdg|tBŸ)¡BB¿YA0h:lj5Bz)5v@BBc@lA
h@n(@aAT)|A^CB=JRBB*-wBBȂA\jd?G+|BkUB¥*@AY/AA
˂A
*gAMAyi|A>CB.gw@BBzorBBƨ`A6zt?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box06AA8y,	ABD>@ȂgAuD=dȂ">{B*2BB?>,4AfE=I	0~=fiBy@BB<>
@!AXE=@/? hA4̂AIGF=ŶAcNN<0AA^-,BB%ɂF)AVhdg|tBŸ)¡BB¿YA0h:lj5Bz)5v@BBc@lA
h@n(@aAT)|A^CB=JRBB*-wBBȂA\jd?G+|BkUB¥*@AY/AA
˂A
*gAMAyi|A>CB.gw@BBzorBBƨ`A6zt?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box07AA8pB%9;=K7<?>;o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box08AA8xorQGqo²skoG?bo6%D@k0A]( x3ߌ?X#A՝A@BdM=WB
49<]U@B ApBR!pBC)&!pB4!pB_;MoQ5yHDovQˆ=oRs~?6o¹$RHC@	@6HGU,7`U}^?ޟQ!ABS BYB&Q@BqWA)pB )pB >')pB/ A)pBw k;io0Gbod8[oC?Uo¥KD@f5U@BnA#pBPf;#pBlP $pB$Pq&$pBOrBO:M \XZo0HSol0Lo1>3?Eo­11D@t22T@[BVvUbA&pBfD;&pBN2&pB&'pB̓BTƜ 1X`A6_7>??2:G2?>;o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box09AA85@oBbQ@@7pB_?@_pB5[@
pB:WcAAQ@AĖ?KQ@YA.YpmAB< &A<M@Vѫ<8\A}oeVTQAs!Ato5fV-AoBobQ@AFpB?AnpB7[ApB	:
AASl@&!N AzofVN Ao->N Aom%N Ao$
@ €&A!
AArZ@@0A-oB	bQ@#0AUpBƓ?0A}	pB9[0ApBo:1AG!ASUAy! Awo"fV Ao-> Ao% Ao6
UA) -&A`1A;
?:F>zAF7o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box10AA8@oDQ@oBY@@o [?8@hp±;@(/xM@I@ڇ?<}c$Aɜ BU(BFM_EB\@bB!AApB>ApB'>ApBE?>ApB6X>RAoEQRAo—[9RAov[?URA<p†;@AifcUAh.UAyׇ?ATu#A؟AJ B؟Ag B
M'ٟAB)\@TٟAB!Ap ApBl>q ApB'>q ApB
?>q ApBW6X>Ao+EQA	o	ZA0o’[?/AXpM;@!GAnS@@B!AXApB|6X>XApB2?>XApB'>XApB>@u BFAuZ1AoEQ1AoZ'1A!o[?B1AKp;@`2AeS@UA7Bg!AApBi6X>ApB ?>ApB'>ApB}>UA B@2AZޟuZ`A6ЕY7s>?)?>;\,!A7o:o:o: Al			



	

	
	

! !"!"#"#! -,- "!.-.!#"/./"-,,.--/..$#$%$%&%&$#0/0#%$101$&%212%0//100211'&'
('(
)()
'&323&('434')(545(322433544*)*+*+ + *)656)+*767* +,7,+655766,770ADefaultl	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkPA                  @@@@@@@@@@@@@@@@@@@Box11AA(AWK>A>YAtU>YA>VA;Q>2Aץ>~ADAlݹ@eu:Ql\:Ct='AﯹAP@~A&CAlݹ@%5:Ql򼷺9>AA1A.>A1A>AAD>A%A87>AESAwkQ>!QA>A4>A>DSAxQ>QA"3>Bi
|K@B@L(oB0>4oBx?0B԰|?Bv'@LBi
*K@B@1*(oB0>44oBx?40B԰*?Bv'@0*򼅫Bi
8=J@B@h8=(oB0>s3=4oBx?t3=/B԰8=?Bw'@h8=Bh
½=J@B@½=(oB0>z=4oBx?z=/B԰½=?Bw'@½=W[A>E>AXA`>AA;>AA
>AT[AE>AXA>ASA>L>lQAV>A0N>iA>%WAQ>UAM5>`ZB/;@O`ZB/;@=*_ZB.;@a8=_ZB.;@½=]Aw>A_A^E>A AӪ>AA#B>AYA)>A[Ao>>AB½=B8=B*B~HAAg=\AqO>8A>AP>A?ACAACA&ACA5:=ACAZĽ=Ax?AhA>AA`:>AApB>A"A==ANAWǽA,Aijý=,AiU8=,AiV*-AiAyOWA-=*UA.P>SA@c>PA>A?&.A~A&.A~A&&.A~A2:=%.A~AYĽ=A^x?AEXAc>AZA>Ak]A/C>A_A~@=AATǽAA{iý=A{S8=A{\*򼒆A{vAP>RAZ>AeP>A>tAQ>PAԥ>׀A@րA@%րA@:=ՀA@DĽ=A4>AxAD>AA	>AFAΏD>AAY>AzA!pD>AWAGdĽ=WAGd(:=WAGd&WAGd쯹`A6s?33ﭦ??`<o:o:o: A,			





		
	




   !!!"""##$%++*$%&,,+%&'--,&'(..-'()//.(*+110*+,221+,-332,-.443-./554.01776012887123998234::9345;;:467==<678>>=789??>89:@@?9:;AA@:<=CCB<=>DDC=>?EED>?@FFE?@AGGF@IIHJJIKKJLLKMMLHI]]\HIJ^^]IJK__^JKL``_KLMaa`L\]qqp\]^rrq]^_ssr^_`tts_`auut`pqpqrqrsrststut%%$&&%''&(('))(NNMOONPPOQQP#RRQMNbbaMNOccbNOPddcOPQeedPQRffeQabvvuabcwwvbcdxxwcdeyyxdefzzyeuvuvwvwxwxyxyzy//)55/;;5AA;GGA#"SSR#"!TTS"! UUT! VVU WWVRSggfRSThhgSTUiihTUVjjiUVWkkjVfg{{zfgh||{ghi}}|hij~~}ijk~jz{z{|{|}|}~}~~FFGEEFDDECCDBBCXXWYYXZZY[[ZHH[WXllkWXYmmlXYZnnmYZ[oonZ[H\\o[klklmlmnmnono\ppop<<B66<006**0$$*0AhDefault,	

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~	

 !"#$%&'()*+PA                                                  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
MAXSCENEdd	
n0Box01@m>pn) &!
d

	I@4h4?dH5?H@D82=^+?;T<8 ?P}2.ʲ?F<#p?P?^qV<'O?MGK㨰<8 ?QųL3?F<625
6?P?qV<'kO~K> &!
d	
I@x6羺?H@F8p<<3Q(q<?a:K22f>?<<8 ?L2~?F5=u%uZ,@=2dQB@f	F?v"&)\?)\?)\?X0Box03@>>Vœ) &!
d	
I@x6羺?H@F8p<<3Q(q<?a:K22f>?<<8 ?L2~?F5=u%uZ,@=2dQB@f	F?v"&)\?)\?)\?X0Box04@>$B) &!
d	
I@x6羺?H@F8p<<3Q(q<?a:K22f>?<<8 ?L2~?F5=u%uZ,@=2dQB@f	F?v"&)\?)\?)\?X0Box05@G>"B) &!
d	
u@˿:˿:H@A8p</3D
5(q<?z{q=662f>?l:+;<8 ?4p3?F5=벆(4Z,@K:3e dRB@g	F?r"&)\?)\?)\?X0Box06@:ٿFœ) &!
d	
u@˿:˿:H@A8p</3D
5(q<?z{q=662f>?l:+;<8 ?4p3?F5=벆(4Z,@K:3e dRB@g	F?r"&)\?)\?)\?n0Box07@>¨# &!
d

@m?,?H@82=pΕ+?Y/<8 ?:X"2?F?囜L>C<8 ?P35W?Fp| &!
d

+I@5045?H@ΰ82=X+?3oB2<8 ?$7>w2?F<'6^?P?IqV<'O?yC4M<8 ?.dLײ?F<cc?P?hqV<'O?پ%<8 ?X2yn?F>dv~;Sa	^B8n0f^utr	.@	`|xo0>y,L!4RF/<|5>Inns%Q[k3mY*Mw>B A~->jj8CCCMYroX18ogg`?cO_	&g7'_rkq@a-8I-&[m,/		;k\fDHM	L	[2]Ry	[rGla7%pW%_Q,X6Yv"lRu>3Qa'{FXCjYM>VXh+[02jr^@mCG7[	

}W!:XR6|sbn
GDme>Bo1A&$(j		L 21h\E5'.Gd9!k4II6\W,{
3!Z"W)uWmt,C

ttoO~hDEhv3FkCB/
%fC
!G\69tx/&--<Fv&$*1E30M0`U
iY{8]W#Q\=L6-rBEg[\=j^tTgF:=xC,2gl	`KDpPPpC{6PA0=/Rx:gt+FD&dM,RBIoy;ca7lY~TBS|Q_268zez{J1xQY/_P
~x%Y:^xdAqUyj&in5e>8W**Xaz;7a}:s5H5yr\fAu@b^2$`1%xQT
uW1>A1ra^L|?>8,5>SD_n
	jmQzIs	_,Zr~YIBxReZ3U@mk_fBm~wZ}8td>st9HcT	!6^;z8Kb-t*<^tI)B?Pr2&r4mq/bLh
{wB.ReRg[g<lVF5%n38Py#<.V#75;]rNsYDl 4- v TDJIw+)y"Pn_a!w{|HgP%1rGL)zBoy6V0OT=bW1VtnD5uq#]N^m^*\.
u-&82cP6c(q
{HiofpMkdo|UX@oHf=}Bs;svC~,6epsrR-
E 7<"/7Cz`k/D(73:i`NKWaG}cu_6n#i']@`l&@'gH8	}-/F3&82V`4YJJsu`n%:l^#1H`>c%eS=,x+RP8D]yzJ[*(,A<1m_2$v,}z@t
<?/;UiTPOy'[L)I[/!(3,
}Wz>,0~zCIf`-@j
40'"
r)%v+SG!0eH{pw(]oa!Re):\YC(`.b/s9l)Q"+N	s+k j_9]UUbu`@6w<%P8e_e40
jp3@P<yhAwiCrl?$={i0t>H "K}%@v2p}GSZ[O]G#PU-b# qWCLX)<
c04~Kp-M+]xH,O{mY`nSgn\Uqozy`FD=
:CoF0T	d7-]EHomJ^GCo_#AjS=~a.V{sbapH%@'eQe# |AgTE;[9-~ufTan/5f0LS>v!,3&|W|11J
(?|x:\]e=CJ!uwUUdIA	\n9#pi>|MoHPY/al/Iv[,up7S	Tt}B^i~[/IWVr$
9} }>-#egn3eCw&MXk*1No"87i+}YT+iYi7,L(SHj?r4	Od.1lQc3{	
nqm9h>"L-JK58z"R08;AJN2eP.WbADs3)
Q;,Mp|,>IggVzc;e'~TD
+Ochft26lE9up_h6eT/GwAytB)7,$%LeP??ze6Le]C,Kd::+Yx.MEj
|u.TF9k4Hjy^c1;m#)+MRf'n)K\tH(Y{PQx6L}`>EBVvqR/B!6@)nOC=8
}#>xt\grtcy!hdeE[,(2n~GaG{XQYN5a#5q|7(b8Go}F&f<igB_Tz]_TV['5n&#:2i0du.e6~nFkp``e{>mswHO+K5*l{)e]9N>

7X&]}ZFQsAL>M47A'77>bW[yl>+@a	'5HQ+%G7%QGRxUh@L*	Iyt	AvaqG\glY
.FNz5U;Lygy%cO(SZ&VS=(g,U/w&yZ(h!J:d5b7/c+M-iI3V{_}bl;_x[^dzLvi'8&l'B+DO-Bkh8Va[MaAr:4X&5hd5\MS~cx^=p2"02W[APU+FUi"IovAux2('.nE9g%YM1h$~CkO=F**8CRTbajapwz,0Dm:&B:ft
~pPYUij{3Wz\Pr4/qu]uKH'c_e3ZuS:. vN{G{S}
Rr	_y.@e2pb\^-vSfy;\o.a'['O"U"kyZ~f?5Nkp(#pDk\bm@6VNY;6c1Ye:yP=@GUz0>5{(2z99kD?ra()E;St$76!#]rO>wK?%~?JV&
kJ 4x_w4Av&F9PC7
8LcCnN8m\*Lat>?M6mV?	/e`%I2nER<:$\q\t[Gc~dNg&&OI,9'Qy_N
%VavB
bJ8Lho	 vOhpp{d%
!G<;aUdzi~$ul3Cej5Xw!X<WJ?X6
KY
&]Nh9db)e8QG4%3_08w}+uf0i*[W	/wV<t}ZJA{#3"jD+h=~2(2U!a5>)(}M9tO1*r-[mDz''TsYK0Y
"1Ex@)w^Ml5dH	R{5.^;umDR}Ffn1)Awt5x#_+G0Pq,KA}|G-,M vv*_$Gdkq 6'u[3]-0$;;Jw6{A_dKbvSA*	fNZ)w]Xn|{d8	\,7XL%2B.?:;t2zvA'P|%V `(D*;i~	h	 uKHw5.V[V7W;!	=cvGxA
uCdJdELk3Fuc.=Kv`'scz>Cky
!fKUbh$vDh"_Y: 8j?Hrn3'Oo~{y1MO\\QsCWm8R
^LGtw7&<<!B3^s(bg0k$,p&E
p2^bt\f@Mb[BZqr%!	6xBCf7ZIpE<KxW`O%mp >]%,	6R)c	"NQ
A@ui
@/&ckI%g/SK)1AuGN)oi
Q]EoLwg.nl+}~$4HLfpG-UDx+GW/F()F@m
\tD)r0e-hjaL@RMu'6Q"QPVQ1V|ZS S)0m
5>U6GOY<a3B^t-sZ
-znME	pru""Rt=>6SlhvK-xal7o+\&@VQIv,xW~XO/$`E<niD68<.k
El);Ke@
zF0*;q8[m0gxNyaw v&f:xqS RVTjyF\s4W['hOGQK)pZ){c{{l5I*Y7;lo5DTMx `hecZwiRk]@5NdDaL62Q>F0Z\PPoJx=](V~`8{IA_'6s5Nw'I].>rI-(llB61)-_vcQNVKb
e4#A2#
o8]
c+GcxZ`hU`FdKG_yS`aELylJZa
Vkv(bE8VkGOFY#DvYVk^

_O#5>WFiXr/>\; Q`RpU#
(gVMU@6F!09hBW7=}pAGW1AT^y
n-X@EM.>c4*H=|\`Z
1SN:ZiCi(BF'
vaNnFB$?{{8adBdD_`XL"1{$'3!Q{'O neOn8IukXrnb8	w?;~k @f+Au?7*xf?VY}j54+EF?i@H)LhX#t>nk"y,|Z26=li{#O;/ !uK4ICDS`VPg9[x7!aa
b3PYP6(8e"#}^h (k%yg6T0`}u~%r<LK8HtG}Ck:;^w5Lc	Ac0`#"O{/v7#QE[*n3scXKW	1mq>9@)h*U/.s~ZS\=~`!/	Q*!2Jet}l[RsmD57D	%t'7k2Mpc+Tl0H5
HV}K?@E=!;ws6S,~@!1&vz};Dx=lRxN[_=l0jUr#?b
?q  [e4s|Y$.5EHZCg(`-L"8	.w1aNDP9H,O{^E3Df|inahdD0n@2N]fx Xto/Djvdiydj^G!*amltG<QJQ"/Yi\*KHJhj@xh(ZF2?^4 cpbNMgT+7Fj=TD2NK6|P?jhgh;]1g.'cV
     } a, b;
     

Exemples

     struct cellule {
         char  **p;
         int    *t[10];
         int   (*f)();
     };

     struct cellule cel1, *cel2;
     struct cellule cel[15];

     struct boite {
         struct cellule  cel1;
         struct cellule *cel2;
         struct boite   *boite_suivante;
         int             ent;
     } b1, b2, *b3;
     


Un champ de bits est un ensemble de bits contigus l'intrieur d'un mme mot.

Le constructeur de structures permet de dfinir un dcoupage mmoire en champs de bits. Les membres de cette structure dsignent les diffrents champs de bits. Ils doivent tre du type unsigned int et indiquer le nombre de bits de chaque champ.

Syntaxe

     struct [ nom ] {
         unsigned int champ1 : longueur1;
         unsigned int champ2 : longueur2;
                   ...
         unsigned int champn : longueurn;
     };
     

Exemple

     struct {
         unsigned int actif  :  1;
         unsigned int type   :  3;
         unsigned int valeur : 14;
         unsigned int suivant: 14;
     } a, b;
     
Un champ peut ne pas avoir de nom. Sa longueur indique alors le nombre de bits que l'on veut ignorer. Une longueur gale 0 permet de forcer l'alignement sur le dbut du mot mmoire suivant.

Exemple


     struct zone {
         unsigned int a:  8;
         unsigned int  :  0;
         unsigned int b:  8;
         unsigned int  :  8;
         unsigned int c: 16;
     };
     struct zone   z1, *z2;
     

Remarques



Le constructeur union permet de dfinir des donnes de type diffrent ayant la mme adresse mmoire.

Syntaxe

     union [ nom ] {
        < liste de dclarations >
     };
     

Remarques

Exemples

     struct complexe {
         float x;
         float y;
     };

     union valeur {
         long   entier;
         float  reel;
         struct complexe complexe;
     };

     enum type {Entier, Reel, Complexe};

     struct nombre {
         enum type    type;
         union valeur valeur;
     };

     struct nombre n;
     

Exemples

     struct zone {
         int      nb_parm;
         char   **parm;
         union {
           unsigned char mask;
           struct {
              unsigned int a: 1;
              unsigned int b: 1;
              unsigned int c: 1;
              unsigned int d: 1;
              unsigned int e: 1;
              unsigned int f: 1;
              unsigned int g: 1;
              unsigned int h: 1;
           } drapeaux;
         } infos;
     } z1, *z2;
     

Retour dbut .

3.7 - Dfinitions de types

Il existe plusieurs manires de se dfinir de nouveaux types :

A la diffrence des constructeurs htrognes qui crent de nouveaux types, le constructeur typedef permet seulement de donner un nouveau nom un type dj existant.

Syntaxe

     typedef < dclaration >
     

Exemples

     typedeflong            size_t;
     typedefunsigned long   Cardinal;
     typedefchar           *va_list;
     typedefstruct complexe Complexe;
     typedefint             Matrice[10][20];

     Complexe  c1, *c2;
     Cardinal  nombre;
     va_list   arg;
     size_t    dimension;
     Matrice   tab, *ptr_mat;

     typedef struct cellule {
         Cardinal        n;
         struct cellule *ptr_suivant;
     } Cellule;

     Cellule cel1, *cel2;
     

Une expression de type est une expression construite en retirant l'objet de la dclaration qui le dfinit.

Exemples

     char     *c;
     int       (*f)();
     char      (*tab)[100];
     char      (*(*x())[6])();
     char      (*(*vec[3])())[5];
     Complexe  (**ptr)[5][4];
     
Les types des objets dclars prcdemment sont donns par les expressions de types suivant :
     char     *
     int      (*)()
     char     (*)[100]
     char     (*(*())[6])()
     char     (*(*[3])())[5]
     Complexe (**)[5][4]
     

Retour dbut


.

4 - Expressions et oprateurs

Retour dbut .

4.1 - Constantes littrales

Constantes entires

Une constante entire peut s'crire dans les systmes dcimal, octal ou hexadcimal.

Une constante entire prfixe :

Une constante entire est par dfaut de type int. Elle est de type long si elle est suffixe par les lettres l ou L et non signe lorsqu'elle est suffixe par les lettres u ou U.

Exemples

base102256178932765
22u56L29UL1L
base 80643017706440755
0177L0222UL0777u0766ul
base160xff0Xabcd0x800X1
0xffL0X1uL0X7fU0x5fUL

Constantes relles

Une constante relle (ou constante en virgule flottante) est un nombre exprim en base 10 contenant un point dcimal et ventuellement un exposant spar du nombre par la lettre e ou E.

Une constante relle est par dfaut de type double. Elle sera du type float si on la suffixe par la lettre f ou F.

Exemples

0.1.0.21789.5629
50000.0.00074312.3315.0066
2E-80.006e-31.66E+83.1415927
1.6021e-19f6.0225e23F2.7182816.6262e-34

Constantes caractres

Une constante caractre est assimile un entier sur un octet dont la valeur correspond au rang du caractre dans la table ASCII.

Une constante caractre est constitue soit :


Squences d'chappement

SyntaxeSq. d'ch.Code ASCII
sonnerie\a7
retour arrire\b8
tabulation h.\t9
tabulation v.\v11
retour la ligne\n10
nouvelle page\f12
retour chariot\r13
guillemets\"34
apostrophe\'39
point d'interr.\?63
antislash\\92
caractre nul\00

Exemples

                          Valeur entire associe
        'A'      ====>            65
        'x'      ====>           120
        '3'      ====>            51
        '$'      ====>            36
        ' '      ====>            32
        '\n'     ====>            10
        '\t'     ====>             9
        '\b'     ====>             8
        '\"'     ====>            34
        '\\'     ====>            92
        '\''     ====>            39
        '\0'     ====>             0
        '\177'   ====>           127
        '\x0a'   ====>            10
        '\000'   ====>             0
  

Constantes chane de caractres

Une constante chane de caractres est une suite de caractres entre guillemets.

En mmoire cette suite de caractres se termine par le caractre NULL ('\0').

La valeur d'une chane de caractres est l'adresse du premier caractre de la chane qui est donc du type pointeur de caractres (char *).

Ne pas confondre "A" et 'A' qui n'ont pas du tout la mme signification !

Pour crire une chane de caractres sur plusieurs lignes on peut :

Exemples

char *chaine = "\
\n\
\t/----------------------------------------------\\\n\
\t| Pour crire une chane sur plusieurs lignes, |\n\
\t|   il suffit de terminer chaque ligne par \\  |\n\
\t\\---------------------------------------------/\n";

char *chaine = "criture d'une "
               "chane de caractres "
               "sur plusieurs "
               "lignes\n\n";
  

Retour dbut .

4.2 - Constantes symboliques

Les constantes symboliques sont de plusieurs types :

Exemple

        char    tab[100];
        double  func(int i)
        {
              ...
        }
        const   int   nombre;
        const   char *ptr1;
        char   const *ptr2;
        char * const  ptr3;
     
Les objets prcdents sont respectivement :

Retour dbut .

4.3 - Oprateurs arithmtiques

Une expression est constitue de variables et constantes (littrales et/ou symboliques) relies par des oprateurs. Il existe 5 oprateurs arithmtiques : Leurs oprandes peuvent tre des entiers ou des rels hormis ceux du dernier qui agit uniquement sur des entiers. Lorsque les types des deux oprandes sont diffrents, il y a conversion implicite dans le type le plus fort suivant certaines rgles.

Rgles de conversions

Les oprateurs + et - admettent des oprandes de type pointeur, ceci pour permettre notamment de faire de la progression d'adresse.

OprateurOp. 1Op. 2Rsultat
+pointeurentierpointeur
+entierpointeurpointeur
-pointeurentierpointeur
-pointeurpointeurentier

Exemples

    char  *pc;
    int   *pi;
    int    a, b, c;
        ...
        ...
    c  = 2*a + b%2;
    pc = pc + a;
    pi = pi - c;
  

Retour dbut .

4.4 - Oprateurs logiques

Le type boolen n'existe pas. Le rsultat d'une expression logique vaut 1 si elle est vraie et 0 sinon. Rciproquement toute valeur non nulle est considre comme vraie et la valeur nulle comme fausse.

Les oprateurs logiques comprennent :

Le rsultat de l'expression :

Exemple

  int   i;
  float f;
  char  c;

  i = 7;
  f = 5.5;
  c = 'w';

  f > 5                    ====>  vrai (1)
  (i + f) <= 1             ====>  faux (0)
  c == 119                 ====>  vrai (1)
  c != 'w'                 ====>  faux (0)
  c >= 10*(i + f)          ====>  faux (0)
  (i >= 6) && (c == 'w')   ====>  vrai (1)
  (i >= 6) || (c == 119)   ====>  vrai (1)
  (f < 11) && (i > 100)    ====>  faux (0)
   

Retour dbut .

4.5 - Oprateur de taille

L'oprateur sizeof renvoie la taille en octets de son oprande. L'oprande est soit une expression soit une expression de type.

Syntaxe

     sizeof  expression
     sizeof (expression-de-type)
     
L'oprateur sizeof appliqu une constante chane de caractres renvoie le nombre de caractres de la chane y compris le caractre NULL de fin de chane.

Si p est un pointeur sur un type t et i un entier :

      l'expression  p + i
      a pour valeur p + i*sizeof(t)
     

Exemples

int menu[1000];
typedef struct cel {
      int         valeur;
      struct cel *ptr;
} CEL;

sizeof menu / sizeof menu[0]
                    ===> nombre d'lments
                         du vecteur menu.

sizeof(long)       ===> taille d'un entier long.
sizeof(float)      ===> taille d'un flottant
                        simple prcision.
sizeof(struct cel) ===> taille d'un objet du
                        type struct cel.
sizeof(CEL)        ===> taille d'un objet du
                        type CEL.
     

Retour dbut .

4.6 - Oprateurs d'adressage et d'indirection

L'oprateur & appliqu un objet renvoie l'adresse de cet objet. L'oprateur * s'applique un pointeur et permet d'effectuer une indirection c'est--dire retourne l'objet point. Si vect est un vecteur, la valeur de la constante symbolique vect est gale &vect[0]. Si a est un objet de type t, &a est de type t *. Rciproquement, si p est un objet de type t *, *p est de type t.

Exemples

        int  u;
        int  v;
        int *pu;
        int *pv;
        typedef struct cel {
           int         valeur;
           struct cel *ptr;
        } CEL;
        CEL  c1, *c2;

        u  = 3 ;
        pu = &u ;
        v  = *pu ;
        pv = &v ;
        c2 = &c1 ;
     

Retour dbut .

4.7 - Oprateur de forage de type

Il est possible d'effectuer des conversions explicites l'aide de l'oprateur de forage de type ou cast.

Syntaxe

     (type) expression
     (expression-de-type) expression
     

Exemples

int    n;
int    tab[100];
int    (*p)[2];
double puissance;

n = 10;
puissance = pow((double)2, (double)n);
p = (int (*)[2])tab;
**(p+49)     = 1756;
*(*(p+49)+1) = 1791;
     

Schma d'adressage
** Schma adressage

La fonction pow est la fonction exponenciation, elle renvoie 2n dans l'exemple prcdent.

Retour dbut .

4.8 - Oprateurs de manipulations de bits

Oprateurs arithmtiques "bit bit"

Ils correspondent aux 4 oprateurs classiques de l'arithmtique boolenne :

Les oprandes sont de type entier. Les oprations s'effectuent bit bit suivant la logique binaire.

b1 b2 ~b1 b1&b2 b1|b2 b1^b2
110110
100011
011011
001000

Exemples

int a, b, c, flag;
int Mask;

a = 0x6db7;
b = 0xa726;
c = a&b ;        ===> 0x2526
c = a|b ;        ===> 0xefb7
c = a^b ;        ===> 0xca91
flag = 0x04;
c = Mask & flag;
c = Mask &  flag;

Oprateurs de dcalage

Il existe 2 oprateurs de dcalage :

Le motif binaire du 1er oprande, qui doit tre un entier, est dcal du nombre de bits indiqu par le 2e oprande.

Dans le cas d'un dcalage gauche les bits les plus gauche sont perdus. Les positions binaires rendues vacantes sont remplies par des 0.

Lors d'un dcalage droite les bits les plus droite sont perdus. Si l'entier dcaler est non sign les positions binaires rendues vacantes sont remplies par des 0, s'il est sign le remplissage s'effectue l'aide du bit de signe.

Exemple

int  etat;
int  oct;
int  ent;
int  a;

a = 0x6db7;
a = a << 6;                 ===>  0x1b6dc0
a = 0x6db7;
a = a >> 6;                 ===>  0x1b6
ent = 0xf0000000;
ent = ent >> 10;            ===>  0xfffc0000
oct = (etat >> 8) & 0xff;
  

Retour dbut .

4.9 - Oprateurs effet de bord

Ce sont des oprateurs qui modifient l'ensemble des valeurs courantes des variables intervenant dans l'valuation d'expressions.

Oprateurs d'affectation

Les oprateurs d'affectation sont :

L'affectation est une expression. La valeur de ce type d'expression est la valeur de l'expression situe droite de l'affectation.

On appelle g-valeur toute expression pouvant figurer gauche d'une affectation. Un identificateur de vecteur n'est pas une g-valeur.

Une expression de la forme :

     e1 op= e2      est quivalente 
     e1 = e1 op e2
     

Exemple

int           valeur;
int           i;
char          c;
unsigned char masque;
int           n;

...

valeur >>= i;
c       &= 0x7f;
masque  |= 0x1 << (n - 1);
masque  &=  (0x1 << (n - 1));
     

Oprateurs d'incrmentation et de dcrmentation

Les oprateurs d'incrmentation (++) et de dcrmentation (--) sont des oprateurs unaires permettant respectivement d'ajouter et de retrancher 1 au contenu de leur oprande.

Cette opration est effectue aprs ou avant l'valuation de l'expression suivant que l'oprateur suit ou prcde son oprande.

Ces oprateurs ne s'appliquent qu' des g-valeurs.

Exemple

int   i;
int   j;
int   tab[100];
char  buffer[2048];
char *ptr;
int  *p_ent;

i = 99;
j = 2;
i++;
p_ent  = tab;
*(p_ent + --i) = ++j;
ptr    = buffer;
*ptr++ = '\n';
    

Retour dbut .

4.10 - Oprateur conditionnel

L'oprateur conditionnel (?:) est un oprateur ternaire. Ses oprandes sont des expressions.

Syntaxe

     expr1 ? expr2 : expr3
     
La valeur de l'expression expr1 est interprte comme un boolen. Si elle est vraie, c'est--dire non nulle, seule l'expression expr2 est value sinon c'est l'expression expr3 qui est value.

La valeur de l'expression conditionnelle est la valeur de l'une des expressions expr2 ou expr3 suivant que l'expression expr1 est vraie ou fausse.

Exemple

int i;
int indic;
int a, b;
int c;

...

indic = (i < 0) ? 0 : 100;
c    += (a > 0 && a <= 10) ? ++a : a/b;
c     = a > b ? a : b;
     

Retour dbut .

4.11 - Oprateur squentiel

L'oprateur squentiel (,) permet de regrouper des sous-expressions sous forme de liste. Ces sous-expressions sont values en squence. La valeur d'une liste d'expressions est celle de la dernire de la liste.

Exemple

int    i;
float  r;
double dble, d;
char  *ptr;
char   buffer[100];

d = (i = 1, r = 2.718f, dble = 2.7182818);
r = (float)(ptr = buffer, i = 10);
     

Retour dbut .

4.12 - Autres oprateurs

Oprateur d'indexation

Cet oprateur ([ ]) permet de rfrencer les diffrents lments d'un vecteur. C'est un oprateur binaire dont l'un des oprandes est un identificateur de vecteur ou un pointeur et l'autre oprande un entier.

Si p est un pointeur ou un identificateur de vecteur et n un entier, alors l'expression p[n] dsigne le (n+1)e lment partir de l'adresse p, c'est--dire l'lment situ l'adresse p+n.

Cette expression est donc quivalente *(p+n).

Exemple

  char  buffer[4096];
  char *ptr;
  int   i;
  int   ta[5], tb[5], tc[5];

  buffer[10] = 'a';
  *(buffer + 9) = 'b';
  i = 0;
  buffer[i++] = 'c';
  i  += 15;
  ptr = buffer + i;
  ptr[0] = 'd';
  *++ptr = 'e';
  *ta = 1, *tb = 2;
  tc[0] = ta[0] + tb[0];
  

Oprateur d'appel de fonction

C'est l'oprateur () qui permet de dclencher l'appel la fonction dont le nom prcde. Ce nom peut tre soit un identificateur de fonction, soit un pointeur de fonction.

A l'intrieur de ces parenthses, apparat ventuellement une liste d'expressions appeles paramtres qui sont values puis transmises la fonction. L'ordre d'valuation de ces expressions est indtermin.

Exemple

char *f(int i, float x);
char *(*pf)(int i, float x);
char *ptr;
int   i;
float x;

i = 2, x = 1.;
ptr = f(i, x);
pf = f;
i = 10, x *= 2.;
ptr = (*pf)(i, x);
/* non portable */
ptr = (*pf)(i++, x = (float)i);
/*              */
i++;
ptr = (*pf)(i, x = (float)i);
     

Oprateurs de slection de champ

L'oprateur . permet d'accder aux champs d'une structure ou d'une union. Il est binaire. Le 1er oprande doit tre une structure ou une union et le 2e oprande doit dsigner l'un de ses champs.

Le type et la valeur de l'expression op1.op2 sont ceux de op2.

Pour accder un champ ch d'une structure ou d'une union pointe par un pointeur ptr, on crira l'expression (*ptr).ch qui est quivalente ptr->ch.

Exemple

typedef struct cellule {
    int    n;
    char  *c;
    int    nb_parm;
    char **parm;
} CEL, *PTR_CEL;
typedef struct boite {
    int     nb_boite;
    PTR_CEL cel;
} BOITE;
CEL     c1;
PTR_CEL ptr_cel;
BOITE   b[10], *p_boite;
c1.n         = 10;
c1.c         = "nom de la cellule";
ptr_cel      = &c1 ;
ptr_cel->n   = 20;
b[0].cel     = ptr_cel;
b->nb_boite  = 5;
b[0].cel->n++;
b->cel->n++;
b[1] = b[0]; p_boite = &b[1];
p_boite->cel = (PTR_CEL)0;
     

Retour dbut


.

5 - Porte et visibilit

Retour dbut .

5.1 - Niveau d'une variable

Le niveau d'une variable est dtermin par l'emplacement de sa dclaration dans le programme.

Exemple

Cardinal  nb_elements;     /* niveau 0 */
size_t    taille;          /* niveau 0 */
main()
{
    int   i, j;            /* niveau 1 */
    char  c;               /* niveau 1 */
    {
        Complexe  c1, *c2; /* niveau 2 */
        int       i;       /* niveau 2 */
        if (...) {
          char car;        /* niveau 3 */
            ...
        }
    }
      ...
}
int   ent;                 /* niveau 0 */
void f(void)
{
    long  i;               /* niveau 1 */
      ...
}

Retour dbut .

5.2 - Dure de vie d'une variable

La dure de vie d'une variable est le temps pendant lequel cette variable a une existence en mmoire. Une variable peut avoir une dure de vie :

Retour dbut .

5.3 - Classes de mmorisation

Il existe quatre classes de mmorisation :

Les classes static et extern concernent les variables permanentes. Les classes auto et register concernent les variables temporaires. C'est au moment de la dclaration des variables que ces attributs peuvent tre spcifis.

Exemples

       extern          int i;
       static unsigned int j;
       register        int n;
     

Retour dbut .

5.4 - Porte d'une variable interne

La porte ou la visibilit d'une variable est l'endroit du programme o elle existe et est accessible. La porte d'une variable interne est le bloc o elle est dclare ainsi que tous les blocs contenus dedans l'exception de ceux dans lesquels cette variable a fait l'objet d'une redclaration. Pour dclarer une variable interne permanente il suffit de mentionner l'attribut static lors de sa dclaration.

Par dfaut, en l'absence d'attribut de classe mmoire, une variable interne est temporaire et reoit l'attribut auto. Ce type de variable est allou dynamiquement dans le << stack >> ou pile d'excution (pile de type LIFO).

Lorsqu'une variable est trs utilise, il peut tre avantageux de demander au compilateur qu'elle soit, dans la mesure du possible, range dans un registre de la machine. Cette possibilit, qui ne peut s'appliquer qu' des variables temporaires, ne sera satisfaite que s'il existe des registres disponibles au format de la donne. C'est l'attribut register spcifi la dclaration qui permet de formuler une telle demande.

Exemple

main()
{
  int a = 1, b = 2;
  a++, b++;
  {
    char b = 'A'; int  x = 10;
    a++, b++, x++;
    {
      int a = 100, y = 200;
      a++, b++, x++, y++;
      {
        char a = 'L'; int  z = -5;
        a++, b++, x++, y++, z++;
      }
      a++, b++, x++, y++;
    }
    a++, b++, x++;
  }
}

Retour dbut .

5.5 - Porte d'une variable externe

A - Programme monofichier

La porte d'une variable externe est l'ensemble du source partir de l'endroit o celle-ci a t dclare.

Cela implique que seules les fonctions dfinies aprs la dclaration des variables externes peuvent y accder.

Dans une fonction, une variable externe est masque lorsqu'elle subit une redclaration au sein de cette fonction.

Exemple

int i = 10;
main()
{
    ...           /* la variable externe r
                     n'est pas visible. */
  {
     int i = 20;  /* dans ce bloc la variable
                     externe i est masque. */
         ...
  }
}
float r = 3.14;
void f(...)
{
    ...
  {
     double r;    /* dans ce bloc la variable
                     externe r est masque. */
         ...
  }
    ...
}

Dans une fonction, il est possible de rendre une variable externe visible si elle ne l'tait pas dj. Il suffit de la rfrencer en indiquant l'attribut extern.

Exemple

double y = 10.123;
   ...
main()
{
  int y;    /* y dclare en externe
               est masque. */
   ...
  {
    extern double y; /* On rend la variable
                         externe y a nouveau
                         accessible.  */
      ...
  }
   ...
}

Exemple

main()
{
   ...     /* la variable externe z
              n'est pas visible */
}
void f(void)
{
   extern float z; /* la variable externe
                      z est visible dans f. */
       ...
}
int g(void)
{
   ...     /* la variable externe z
              n'est pas visible */
}
float z = 2.0;
float h(int i)
{
   /* la variable externe z
      est visible dans h ainsi que
      dans les fonctions suivantes. */
}

B - Programme multifichiers

L'unit de compilation est le fichier. Les diffrents fichiers sources constituant une application sont donc traits de faon indpendante par le compilateur.

Lorsque l'on a besoin de partager une variable entre ces diffrents fichiers, on devra allouer son emplacement mmoire dans un seul de ces fichiers et la rfrencer dans les autres. On parlera de dfinition lorsque la mmoire est alloue et de dclaration lors d'une rfrence.

Tous les compilateurs (avant et aprs la norme) considrent :

Les compilateurs de l'aprs-norme admettent l'attribut extern dans les deux cas. Pour ceux-l une simple initialisation suffit pour indiquer une dfinition.

Exemple

source1.c

main()
{
   ...
}
extern int i; /* dclaration de la
                  variable externe i. */
void f(int a)
{
   ...
}

source2.c

int i = 11; /* dfinition de la
                variable externe i. */
int g(void)
{
   ...
}
source3.c
float h(void)
{
   ...
}
extern int i; /* dclaration de la
                  variable externe i. */
void func(void)
{
   ...
}
De plus la norme dit qu'une variable sans l'attribut extern et sans initialisation fait l'objet d'une dfinition potentielle.

Si pour une variable n'apparassent que des dfinitions potentielles, l'une sera considre comme dfinition et les autres comme dclarations. Cette variable sera initialise avec des zros binaires.

Exemple

  sourceA         sourceB          sourceC
int x = 10;   | extern int x;    | extern int x;
extern int y; | extern int y;    | extern int y;
int z;        | extern int z;    | extern int z;
int a;        |                  | int a;
int b = 20;   | int b = 21;      |
int c;        | int c = 30;      |
              |                  |
main()        | int calcul(void) | int somme(void)
{             | {                | {
    ...       |       ...        |      ...
}             | }                | }

On peut limiter la porte d'une variable au source au sein duquel elle est dfinie. Pour cela on indiquera l'attribut static au moment de sa dfinition.

Exemple

      sourceA               sourceB
static float r = 2.154;  |  void f2(void)
double dble = 17.89;     |  {
main()                   |     ...
{                        |  }
   ...                   |  extern double dble;
}                        |  int f3(int i)
float f1(void)           |  {
{                        |     ...
   ...                   |  }
}                        |  static int n = 10;
                         |  void f4(float r)
                         |  {
                         |     ...
                         |  }

Retour dbut .

5.6 - Initialisation des variables

Il est possible d'initialiser une variable lors de sa dclaration.

Syntaxe

     type construction = expression;
     

L'initialisation des variables permanentes doit se faire l'aide d'expressions constantes :
Par contre l'initialisation des variables temporaires peut se faire l'aide d'expressions quelconques.

Exemple

static int   n    = 10 ;
static char *ptr  = "Aix-en-Provence" ;
static int  *p    = &n ;
static int   etat = 0x1 << 5 ;
int flag = etat;               <==>  int flag;
                                     flag = etat;
     
L'initialisation des vecteurs, des structures ou des unions s'effectue au moyen de listes de valeurs entre accolades :
         {val1, val2, ..., valn}
     

Si l'lment d'un vecteur est lui-mme un vecteur on applique rcursivement la notation prcdente. L'initialisation des vecteurs doit se faire au moyen d'expressions constantes.

Seule la premire composante d'une union peut tre initialise.

Exemple

int   tab1[5] = { 2, 6, 8, 10, 17};
int   tab2[]  = { 3, 7, 10, 18, 16, 3, 1};
char  v1[]    = "Wolfgang Amadeus Mozart";
char  v2[]    = "musique";
char  v3[]    = {'m', 'u', 's', 'i',
                 'q', 'u', 'e', '\0'};
char *p       = "musique";
typedef struct date {
   int   jour, mois, annee;
} Date;
typedef struct {
   char  sexe;
   char *nom;
   Date  annee_naiss;
} Individu;
Individu tab[] = {
           {'F', "France Nathalie", {1,  7, 65}},
           {'M', "Deneau Michel",   {8, 10, 61}}
                 };
union donnees {
   int   i;
   float r;
} u = {2};
     

Exemple

int tab[3][4] = {
                  {1, 2,  7, 11},
                  {2, 3, 12, 13},
                  {4, 8, 10, 11}
                };
int t1[][4]   = {
                  {1},
                  {2, 3},
                  {4, 8, 10}
                };
int t2[3][4]  = {1, 0, 0, 0, 2, 3, 0, 0,
                 4, 8, 10, 0};
int t3[][3]   = {0, 1, 2, 3, 8, 9, 9, 1};
int t4[2][3][4] = {
                    {
                       {1, 2, 3, 8},
                       {3, 2},
                       {1}
                    },
                    {
                       {3, 4, 9},
                       {2}
                    } };
     

Retour dbut .

5.7 - Visibilit des fonctions

La dfinition d'une fonction comprend un en-tte (appel prototype), indiquant le type de la valeur qu'elle retourne ainsi que la liste et le type des arguments transmis, et une instruction compose (appele corps de la fonction), renfermant des dclarations d'objets et des instructions excutables.

La dclaration d'une fonction s'effectue au moyen de son prototype.

Lors de l'appel une fonction, pour que le compilateur connaisse le type de la valeur qu'elle retourne et puisse vrifier le nombre ainsi que le type des arguments transmis, il est ncessaire qu'il ait visibilit sur le prototype de cette fonction.

Cette visibilit existe lorsque :

Lorsque que le compilateur n'a pas cette visibilit, il suppose que la valeur retourne par la fonction est de type int.

Une fonction ne peut tre contenue dans une autre fonction, de ce fait toutes les fonctions sont externes. C'est pourquoi prciser l'attribut extern, que ce soit lors de la dclaration ou lors de la dfinition de la fonction, n'apporte aucune information supplmentaire.

A l'instar des variables, une fonction peut n'tre connue que dans le fichier dans lequel elle a t dfinie. Pour cela on indiquera l'attribut static lors de sa dfinition.

Exemple


      sourceA              sourceB
float f(double d);       |  int g(void)
main()                   |  {
{                        |     int i;
   float  r;             |     int j;
   double d;             |     static int h(int i);
                         |       ...
   r = f(d);             |     j = h(i);
   ...                   |  }
}                        |  void func(int i)
static float f(double d) |  {
{                        |   /* la fonction h n'est
   int g(void);          |      pas visible ici. */
   int i;                |  }
                         |  static int h(int i)
   i = g();              |  {
   ...                   |     ...
}                        |  }

Retour dbut


.

6 - Instructions

Retour dbut .

6.1 - Instructions lmentaires

Une instruction lmentaire est une expression termine par un ;.

Contrairement aux expressions, les instructions n'ont ni type ni valeur. Lorsqu'on forme une instruction partir d'une expression la valeur de cette dernire est perdue.

N'importe quelle expression peut former une instruction, mme lorsqu'elle ne gnre pas d'effet de bord.

Une instruction compose ou bloc est un ensemble d'instructions lmentaires et/ou composes, prcdes ventuellement de dclarations, dlimit par des accolades.

Exemple

#include <stdio.h>
#include <math.h>
main()
{
  int    i = 10;
  double r = acos(-1.);

  i *= 2;
  {
     double cosh_pi;

     cosh_pi = (exp(r) + exp(-r)) / 2;
     printf("cosh_pi : %f\n", cosh_pi);
  }
}
   

Retour dbut .

6.2 - Structures de contrle

Les structures de contrle sont les tests, les boucles et l'aiguillage.
.

6.2.1 - Les tests : syntaxe

     if (expression)
        partie-alors
     [else
        partie-sinon]
     

La partie-alors et la partie-sinon peuvent tre indiffremment une instruction lmentaire ou compose.

La partie-alors sera excute si la valeur de l'expression entre parenthses est non nulle. Sinon, si le test comporte une partie-sinon c'est celle-ci qui sera excute.

Exemple

char buffer[2048];
void f(void)
{
   static char *p = (char *)0;

   if (!p)
     p = buffer;
   else {
     *p = '1';
     p++;
   }
}
     

Si plusieurs tests sont imbriqus, chaque partie-sinon est relie au if le plus proche qui n'est pas dj associ une partie-sinon.

Exemple

if (x > 0)                   if (x > 0)
  ecrire("positif");           ecrire("positif");
else if (x < 0)       <==>   else
  ecrire("negatif");         {
else                           if (x < 0)
  ecrire("nul");                 ecrire("negatif");
                               else
                                 ecrire("nul");
                             }
     

Retour dbut .

6.2.2 - Les boucles "tant-que" : syntaxe

     while (expression)
         corps-de-boucle

     do
         corps-de-boucle
     while (expression);
     

La partie corps-de-boucle peut tre soit une instruction lmentaire soit une instruction compose.

Dans la boucle while le test de continuation s'effectue avant d'entamer le corps-de-boucle qui, de ce fait, peut ne jamais s'excuter.

Par contre dans la boucle do-while ce test est effectu aprs le corps-de-boucle, lequel sera alors excut au moins une fois.

Exemple

#include <stdio.h>
main()
{
   int chiffre = 0;

   printf("Boucle \"while\"\n\n");
   while (chiffre) {
      printf(" %d", chiffre++);
      if (!(chiffre%5))
        printf("\n");
   }
   printf("Boucle \"do-while\"\n\n");
   do {
      printf(" %3d", ++chiffre);
      if (!(chiffre%5))
        printf("\n");
      if (chiffre == 100)
        chiffre = 0;
   }
   while (chiffre);
}
     

Retour dbut .

6.2.3 - La boucle "pour" : syntaxe

     for ([expr1]; [expr2]; [expr3])
         corps-de-boucle
     

L'expression expr1 est value une seule fois, au dbut de l'excution de la boucle.

L'expression expr2 est value et teste avant chaque passage dans la boucle.

L'expression expr3 est value aprs chaque passage.

Ces 3 expressions jouent respectivement le rle :

Exemple

main()
{
  int   tab[] = {1, 2, 9, 10, 7, 8, 11};
  int   i, j;
  char  buffer[] = "Voici une chaine"
                   " qui se termine "
                   "par un blanc ";
  char *p;
  int   t[4][3];

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

  for (p=buffer; *p; p++)
       ;
  *--p = '\0';
  printf("buffer : %s$\n", buffer);
  for (i=0; i < 4; i++)
    for (j=0; j < 3; j++)
      t[i][j] = i + j;
}
     

Retour dbut .

6.2.4 - L'aiguillage

L'instruction switch dfinit un aiguillage qui permet d'effectuer un branchement une tiquette de cas en fonction de la valeur d'une expression.

Syntaxe

     switch (expression)
     {
        case etiq1 :
        [ liste d'instructions ]
        case etiq2 :
        [ liste d'instructions ]
              ...
        case etiqn :
        [ liste d'instructions ]
     [ default:
        [ liste d'instructions ]]
     }
     

Les tiquettes de cas (etiq1, etiq2, ..., etiqn) doivent tre des expressions constantes.

Une fois le branchement l'tiquette de cas correspondante effectu, l'excution se poursuit, par dfaut, jusqu' la fin du bloc switch. L'instruction d'chappement break; permet de forcer la sortie du bloc.

L'expression indique au niveau du switch doit tre de type entier.

Exemple

#include <stdio.h>
main()
{
  char *buffer = "\nCeci est une chaine\n"
                 "de caracteres\tsur\n\n"
                 "plusieurs     lignes.\n";
  int   NbCar  = 0, NbEsp = 0, NbLignes = 0;

  for (; *buffer; buffer++, NbCar++)
    switch (*buffer) {
      case '\n': NbLignes++;
                 break;
      case '\t':
      case ' ' : NbEsp++;
      default  : break;
    }
  printf("NbCar = %d, NbEsp = %d, NbLignes = %d\n",
          NbCar, NbEsp, NbLignes);
}
     

Retour dbut .

6.3 - Instructions d'chappement

Ces instructions permettent de rompre le droulement squentiel d'une suite d'instructions.

Instruction continue;

Le rle de l'instruction continue; est de forcer le passage l'itration suivante de la boucle la plus proche.

Exemple

#include <stdio.h>
main()
{
  char *buffer = "\nCeci est une chaine\n"
                 "de caracteres\tsur\n\n"
                 "plusieurs     lignes.\n";
  int   NbCar  = 0, NbEsp = 0, NbLignes = 0;

  for (; *buffer; buffer++) {
    switch (*buffer) {
      case '\n': NbLignes++;
                 break;
      case '\t': continue;
      case ' ' : NbEsp++;
      default  : break;
    }
    NbCar++;
  }
  printf("NbCar = %d, NbEsp = %d, NbLignes = %d\n",
          NbCar, NbEsp, NbLignes);
}
     

Instruction break;

L'instruction break; permet de quitter la boucle ou l'aiguillage le plus proche.

Exemple

#include <stdio.h>
main()
{
   char *buffer = "Wolfgang Amadeus Mozart\n"
                  " est un musicien divin.\n";
   char *p;

   for (p=buffer; *p; p++)
     if (*p == '\n')
     {
       *p = '\0';
       break;
     }
   printf("Nom : %s\n", buffer);
}
     

Instruction return; : syntaxe

     return [expression];
     

Cette instruction permet de sortir de la fonction qui la contient :

Exemple

#include <stdio.h>
void main()
{
   char c;
   char majus(char c);

     ...

   printf("%c\n", majus(c));
   return;
}
char majus(char c)
{
   return c >= 'a' && c <= 'z' ?
          c + 'A' - 'a' : c;
}
     

Instruction go to;

Cette instruction sert effectuer un transfert inconditionnel vers une autre partie du programme.

Syntaxe

     goto tiquette;
     

Etiquette fait rfrence une instruction tiquete. On utilisera cette instruction avec parcimonie car elle nuit l'criture de programme structur. Elle peut la rigueur tre utilise lorsque l'on dsire sortir de plusieurs boucles imbriques, ce que ne permet pas l'instruction break;.

Exemple

#include <stdio.h>
main()
{
   int tab[][4] = {1, 2, 8, 9, 10, 12, 1, 9, 5};
   int i, j;

   for (i=0; i < sizeof tab / sizeof tab[0]; i++)
     for (j=0; j < 4; j++)
       if (tab[i][j] == 10)
         goto trouve;

   fprintf(stderr, "Element non trouve.\n");
   return 1;

trouve:
   printf("L'lment tab[%d][%d]"
          " est gal  10.\n", i, j);
}
     


Un programme peut tre interrompu au moyen de la fonction exit.

Syntaxe

     exit(expression);
     

L'argument de cette fonction doit tre un entier indiquant le code de terminaison du processus.

Exemple

#include <stdio.h>
main()
{
   int tab[][4] = {1, 2, 8, 9, 10, 12, 1, 9, 5};
   int i, j;

   for (i=0; i < sizeof tab / sizeof tab[0]; i++)
     for (j=0; j < 4; j++)
       if (tab[i][j] == 10) {
         printf("L'lment tab[%d][%d]"
                " est gal  10.\n", i, j);
         return 0;
       }
   fprintf(stderr, "Element non trouve.\n");
   exit(1);
}
     

Retour dbut


.

7 - Prprocesseur

Retour dbut .

7.1 - Introduction

Le prprocesseur effectue un prtraitement du programme source avant qu'il soit compil.

Ce prprocesseur excute des instructions particulires appeles directives.

Ces directives sont identifies par le caractre # en tte. Elles peuvent se continuer sur plusieurs lignes, chaque ligne continuer tant termine par le caractre \ suivi d'un return.

Retour dbut .

7.2 - Pseudo-constantes

La directive #define permet la dfinition de pseudo-constantes.

Une pseudo-constante est un identificateur compos de lettres et de chiffres commenant par une lettre. (Le caractre _ est considr comme une lettre).

Syntaxe

    #define identificateur [chane-de-substitution]
    

Le prprocesseur remplace tous les mots du fichier source identiques l'identificateur par la chane-de-substitution.

On prfrera n'utiliser que des majuscules pour crire ces identificateurs afin de les diffrencier des autres (variables, vecteurs, fonctions).

Exemple

#define  TAILLE 256
#define  TAILLE_EN_OCTETS \
          TAILLE*sizeof(int)
main()
{
   int  tab[TAILLE];
   int  i;

   for(i=0; i < TAILLE; i++)
     tab[i] = i;
   printf("Le tableau tab contient %d octets\n",
          TAILLE_EN_OCTETS);
}
    

Remarque

La directive #undef permet d'annuler la dfinition d'une pseudo-constante.

Pseudo-constantes prdfinies

La plupart des prprocesseurs reconnaissent les pseudo-constantes prdfinies suivantes :

Retour dbut .

7.3 - Pseudo-fonctions


Les pseudo-fonctions ou macros sont des substitutions paramtrables.

Exemple

#define ABS(x) x>0 ? x : -x
#define NB_ELEMENTS(t) sizeof t / sizeof t[0]
#include <stdio.h>
#include <math.h>
main()
{
  int    tab[][2] = { 1,  2,  3,  9,
                     10, 11, 13, 16};
  double r = -acos(-1.);
  int    i, j;

  for(i=0; i < NB_ELEMENTS(tab); i++)
    for(j=0; j < 2; j++)
      tab[i][j] = i + j;

  printf("%f\n", ABS(r));
}
    

Remarques


Exemple

#define CARRE(x)   x*x
main()
{
    float x = 1.12;
/*
    Erreur : l'instruction suivante
             calcule 2*x+1 et non pas
             le carre de x+1.
*/
    printf("%f\n", CARRE(x+1));
}
    

Exemple

#define CARRE(x)   (x)*(x)
#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )
main()
{
    float x = 3.1, y = 4.15;
    printf("%f\n", CARRE(x+1));
    printf("%f\n", MAX(x+10., y));
/*
    Erreur : l'instruction suivante
             provoque une double
             incrmentation de x.
*/
    y = CARRE(x++);
}
    

Retour dbut .

7.4 - Inclusion de fichiers

La directive #include permet d'insrer le contenu d'un fichier dans un autre.

Ce mcanisme est en gnral rserv l'inclusion de fichiers appels fichiers en-tte contenant des dclarations de fonctions, de variables externes, de pseudo-constantes et pseudo-fonctions, de dfinition de types. Ces fichiers sont traditionnellement suffixs par .h.

Syntaxe

    #include <nom-de-fichier>
    #include "nom-de-fichier"
    
Si le nom du fichier est spcifi entre guillemets, il est recherch dans le rpertoire courant. On peut indiquer d'autres rpertoires de recherche au moyen de l'option -I de la commande cc.

Si le nom du fichier est spcifi entre <>, il est recherch par dfaut dans le rpertoire /usr/include.

Exemple

def.h

#define  NbElements(t)  sizeof t / sizeof t[0]
#define  TAILLE 256
typedef struct cellule {
     int tab[TAILLE];
     struct cellule *ptr;
} CEL;
typedef enum bool {FAUX, VRAI} logical;
extern void init(int t[], logical imp);
CEL c;
    
#include "def.h"
main()
{
   int t[TAILLE] = {1, 2, 9, 10};
   logical imp = VRAI;

   init(t, imp);
}

    
#include "def.h"
#include 
void init(int t[], logical imp)
{
   int i;

   for(i=0; i < NbElements(c.tab); i++) {
     c.tab[i] = t[i];
     if (imp)
       printf(" %d", c.tab[i]);
   }
   printf("%s", imp ? "\n" : "");
   c.ptr = NULL;
}
    

Il existe une bibliothque standard de fichiers en-tte ncessaires lors de l'appel de certaines fonctions :

Retour dbut .

7.5 - Compilation conditionnelle


Test d'existence d'une pseudo-constante

Ce sont les directives #ifdef et #ifndef qui permettent de tester l'existence d'une pseudo-constante.

Syntaxe

    #ifdef identificateur
       partie-alors
    [#else
       partie-sinon]
    #endif

    #ifndef identificateur
       partie-alors
    [#else
       partie-sinon]
    #endif
    

Exemple

      def.h               source.c
  #ifdef TAILLE_BUF
  # undef TAILLE_BUF
  #endif /* TAILLE_BUF */
  #define TAILLE_BUF 4096
  
#ifdef DEBUG            |  #define DEBUG
  #define trace(s) \    |  #include "def.h"
          printf s      |  #include <stdio.h>
#else                   |  main()
#define trace(s)        | {
#endif/* DEBUG */       |     int f(float x);
                        |     int i;
                        |     float r;
                        |
                        |     i = f(r);
                        |     trace(("%d\n", i));
                        |  }
  
La dfinition d'une pseudo-constante ainsi que sa valorisation peuvent se faire l'appel de la commande cc au moyen de l'option -D.

Syntaxe

  cc -Dpseudo-constante[=valeur] ...
  

On peut appliquer ce principe la pseudo-constante DEBUG de l'exemple prcdent au lieu de la dfinir dans le fichier source.c :
            cc -DDEBUG source.c
  

valuation de pseudo-expressions

Il est possible de construire des expressions interprtables par le prprocesseur l'aide :

Syntaxe

     #if pseudo-expression
        partie-alors
     [#else
        partie-sinon]
     #endif
     

Remarque

Si l'on dsire mettre en commentaire une portion de programme, la solution consistant l'encadrer par les caractres /* et */ ne marche pas si elle contient elle-mme des commentaires.

Une solution simple est de placer en tte de la rgion commenter la directive #if 0, et la fin la directive #endif /* 0 */.

Exemple

source.c

#define TBLOC 256
#if !defined  TAILLE
#  define TAILLE TBLOC
#endif
#if TAILLE%TBLOC == 0
#  define TAILLEMAX TAILLE
#else
#  define TAILLEMAX ((TAILLE/TBLOC+1)*TBLOC)
#endif
static char buffer[TAILLEMAX];
main()
{
   printf("Taille du vecteur : %d caractres\n",
          sizeof buffer);
}
     
  1. cc -DTAILLE=255 source.c
  2. cc -DTAILLE=257 source.c
  3. cc source.c

Retour dbut


.

8 - Les fonctions

Retour dbut .

8.1 - Passage arguments-paramtres

Dans les langages de programmation il existe deux techniques de passage d'arguments :

Des langages comme Fortran ou PL/1 ont choisi la 1re solution, tandis qu'un langage comme Pascal offre les deux possibilits au programmeur.

Le langage C a choisi la 2e solution.

Si un argument doit tre pass par adresse, c'est le programmeur qui en prend l'initiative et ceci grce l'oprateur d'adressage (&).

Exemple

#include <stdio.h>
void main()
{
   int a, b, c;
   void somme(int a, int b, int *c);

   a = 3;
   b = 8;
   somme(a, b, &c);
   printf("Somme de a et b : %d\n", c);

   return;
}

void somme(int a, int b, int *c)
{
   *c = a + b;

   return;
}
     

Retour dbut .

8.2 - Fonction retournant un pointeur

Il convient d'tre prudent lors de l'utilisation d'une fonction retournant un pointeur. Il faudra viter l'erreur qui consiste retourner l'adresse d'une variable temporaire.

Exemple

#include <stdio.h>
void main()
{
   char *p;
   char *ini_car(void);
   p = ini_car();
   printf("%c\n", *p);
}
char *ini_car(void)
{
   char c;
   c = '#';
   return(&c);     <===  ERREUR
}
     

Retour dbut .

8.3 - Passage d'un vecteur comme argument


Un vecteur est une constante symbolique dont la valeur est l'adresse de son 1er lment.

Lorsqu'un vecteur est pass en argument, c'est donc l'adresse de son 1er lment qui est transmise par valeur.

Exemple

#define NbElements(t) sizeof t / sizeof t[0]
#include <stdio.h>
main()
{
   int  tab[] = { 1, 9, 10, 14, 18};
   int  somme(int t[], int n);
   void impression(int *t, int n);
   printf("%d\n", somme(tab, NbElements(tab)));
   impression(tab, NbElements(tab));
}
int  somme(int t[], int n)
{
   int i, som=0;
   for (i=0; i < n; i++) som += t[i];
   return som;
}
void impression(int *t, int n)
{
   int i=0, *p;
   for (p=t; t-p < n; t++)
      printf("t[%d] = %d\n", i++, *t);
}
     

Exemple

#define NbElements(t) sizeof t / sizeof t[0]
#include <stdio.h>
main()
{
   int tab[][5] = {
                     { 4, 7, 1, 9, 6},
                     { 5, 9, 3, 4, 2},
                     { 2, 9, 5, 9, 13}
                  };
   int somme(int (*t)[5], int n);

   printf("Somme des lments de tab : %d\n",
           somme(tab, NbElements(tab)));
}
int somme(int (*t)[5], int n)
{
   int i, som = 0;
   int (*p)[5] = t;
   for(; t-p < n; t++)
     for (i=0; i < 5; i++)
        som += (*t)[i];
   return som;
}
     

Exemple

#define DIM1 10
#define DIM2  4
#define DIM3  5
#include <stdio.h>
main()
{
   int tab[DIM1][DIM2][DIM3];
   void init(int (*t)[DIM3], int n);
   int i, n = DIM2;

   for(i=0; i < DIM1; i++)
     init(tab[i], i);
}
void init(int (*t)[DIM3], int n)
{
   int i, j;

   for(i=0; i < DIM2; i++)
     for(j=0; j < DIM3; j++) {
       t[i][j]      = 2*(i+n*DIM2);
       *(*(t+i)+j) += 1;
     }
}
     

Retour dbut .

8.4 - Passage d'une fonction comme argument


Le nom d'une fonction est une constante symbolique dont la valeur est un pointeur sur la 1re instruction excutable du code machine de la fonction.
Passer une fonction en argument, c'est donc transmettre l'adresse, par valeur, du dbut du code machine constituant cette fonction.

Exemple

double integrale(double b_inf, double b_sup,
                 int pas, double (*f)(double));
double carre(double x);
void main()
{
   double b_inf, b_sup, aire;
   int    pas;
   b_inf = 1., b_sup = 6., pas = 2000;
   aire = integrale(b_inf, b_sup, pas, carre);
   printf("Aire : %f\n", aire);
}
double integrale(double b_inf, double b_sup,
                 int pas, double (*f)(double))
{
   double surface = 0., h;
   int    i;
   h = (b_sup - b_inf)/pas;
   for(i=0; i < pas; i++)
     surface += h*(*f)(b_inf+i*h);
   return surface;
}
double carre(double x) {return x*x;}
     

Retour dbut .

8.5 - Passage d'arguments la fonction main

Lorsqu'un excutable est lanc sous un interprte de commandes ({shell}), un processus est cr et son excution commence par la fonction main laquelle des arguments sont transmis aprs avoir t gnrs par le shell.

Ces arguments sont constitus de :


Les premier et dernier sont transmis sous forme de vecteurs de pointeurs de caractres.

Par convention :


Les arguments prcdents sont transmis la fonction main dans cet ordre.

Exemple

La commande a.out toto titi tata gnre la structure de donnes suivante :

Tableau des arguments

*** Schma ***

Exemple

#include <stdio.h>
main(int argc, char **argv, char **envp)
{
   void usage(char *s);

   if (argc != 3)
     usage(argv[0]);
   for(; *argv; argv++)
     printf("%s\n", *argv);
   for(; *envp; envp++)
     printf("%s\n", *envp);
}

void usage(char *s)
{
   fprintf(stderr, "usage : %s arg1 arg2\n", s);
   exit(1);
}
     

Retour dbut .

8.6 - Fonction avec un nombre variable d'arguments

Lors de l'appel une fonction, le compilateur gnre une liste des arguments fournis qu'il empile dans la pile d'excution rattache au processus (pile de type LIFO).

Exemple

int puissance(int n, int x)
{
  int p = 1;
  while(n--) p *= x;
  return p;
}
void main()
{
  int m, k, r;
  k = 4; m = 2;
  r = puissance(k+3, m);
}
    

A l'appel de la fonction puissance de l'exemple prcdent il y a :

Processus de passage d'arguments

Schma

Ce type de passage d'arguments permet d'crire des fonctions avec un nombre variable d'arguments.

Dans le prototype d'une telle fonction, on indiquera les arguments suivis de :

Comme les arguments sont rangs de faon conscutive dans la pile, le programmeur a la possibilit d'aller chercher les arguments en surnombre.

Exemple

void fonction(int a, ...);
main()
{
   int i = 10, j = 11, k = 12;
   printf("Avant appel fonction i = %d\n", i);
   printf("Avant appel fonction j = %d\n", j);
   printf("Avant appel fonction k = %d\n", k);
   fonction(i, j, k);
}
void fonction(int a, ...)
{
   printf("Valeur de a = %d\n", a);
   printf("Rcupration de j = %d\n", *(&a + 1));
   printf("Rcupration de k = %d\n", *(&a + 2));
}
     
Cette technique de rcupration d'arguments dans la pile, ncessite cependant que le programmeur connaisse les types des arguments en surnombre et qu'il ait un moyen d'arrter la recherche.

Pour ce faire, le dernier argument fourni l'appel de la fonction peut par exemple indiquer le nombre d'arguments en surnombre, ou bien ceux-ci peuvent tre suivis par un argument supplmentaire de mme type avec une valeur spciale (valeur sentinelle).

Par contre la norme ne prcise pas l'ordre dans lequel les arguments doivent tre empils, cette mthode de la pile n'est donc pas portable.

Pour assurer cette portabilit, chaque systme propose des pseudo-constantes et pseudo-fonctions permettant au programmeur de grer cette recherche.

Version Unix System V

Les pseudo-constantes et pseudo-fonctions sont stockes dans le fichier en-tte varargs.h :

Exemple

#include <stdio.h>
#include <varargs.h>
main()
{
   int moyenne();
   printf("moyenne = %d\n", moyenne(4, 1, 2, 3, 4));
   printf("moyenne = %d\n",
           moyenne(5, 1, 2, 3, 4, 5));
}
int moyenne(nombre, va_alist)
int nombre;
va_dcl
{
   int     somme = 0, i;
   va_list arg;
   va_start(arg);
   for(i=0; i < nombre; i++)
     somme += va_arg(arg, int);
   va_end(arg);
   return somme/nombre;
}
     

Exemple

#include <stdio.h>
#include <varargs.h>
main()
{
   float moyenne();
   printf("moyenne = %f\n",
           moyenne(4, 1.f, 2.f, 3.f, 4.f));
   printf("moyenne = %f\n",
           moyenne(5, 1.f, 2.f, 3.f, 4.f, 5.f));
}
float moyenne(nombre, va_alist)
int nombre;
va_dcl
{
   float   somme = 0.f;
   int     i;
   va_list arg;
   va_start(arg);
   for(i=0; i < nombre; i++)
     somme += va_arg(arg, double);  ===> surtout
   va_end(arg);                          pas float!
   return somme/nombre;
}
     

Version ANSI

Les pseudo-constantes et pseudo-fonctions sont stockes dans le fichier en-tte stdarg.h :

Les arguments en surnombre sont symboliss par ... dans le prototype de la fonction.

Exemple

#include <stdio.h>
#include <stdarg.h>
main()
{
   int moyenne(int nombre, ...);
   printf("moyenne = %d\n", moyenne(4, 1, 2, 3, 4));
   printf("moyenne = %d\n",
           moyenne(5, 1, 2, 3, 4, 5));
}
int moyenne(int nombre, ...)
{
   int     somme = 0, i;
   va_list arg;
   va_start(arg, nombre);
   for(i=0; i < nombre; i++)
     somme += va_arg(arg, int);
   va_end(arg);
   return somme/nombre;
}
     
Retour dbut


.

9 - La bibliothque standard

Retour dbut .

9.1 - Notion de pointeur gnrique

La norme a dfini le type void * ou pointeur gnrique afin de faciliter la manipulation des pointeurs et des objets points indpendamment de leur type.

On ne pourra pas appliquer les oprateurs d'indirection et d'auto-incrmentation, auto-dcrmentation un pointeur gnrique.

Par contre, si p et q sont deux pointeurs, les affectations :

sont toutes deux correctes si l'un au moins des deux pointeurs p ou q est de type void *, quel que soit le type de l'autre pointeur.

Exemples

int x[5], i, *k;
float *r;
void  *p;
void  *q;

p = &x[0];       /* correct  */
*p = ...         /* interdit */
q = p + 1;       /* interdit */
r = p;           /* correct  */
p = r;           /* correct  */
p[1] = ...;      /* interdit */
    

Exemples

void echange (void *p, void *q)
{
  void *r;

   r          = *(void **)p;
  *(void **)p = *(void **)q;
  *(void **)q =  r;
}
main()
{
  int    *i1, *i2;
  float  *f1, *f2;
  double *d1, *d2;
      ...
  echange(&i1, &i2);
  echange(&f1, &f2);
  echange(&d1, &d2);
}
    

Retour dbut .

9.2 - Entres-sorties de haut niveau


Les entres-sorties de haut niveau intgrent deux mcanismes distincts : Toute opration d'entre-sortie se fera par l'intermdiaire d'un flot (stream) qui est une structure de donnes faisant rfrence :

Cette structure de donnes est un objet de type FILE. Dans le programme, un flot sera dclar de type FILE *.
Trois flots sont prdfinis au lancement d'un processus :

Les informations prcdentes sont contenues dans le fichier en-tte stdio.h. Ce fichier contient, de plus, les dclarations des diffrentes fonctions d'entre-sortie, ainsi que la dclaration d'un vecteur (_iob) de type FILE dont la dimension est dfinie l'aide d'une pseudo-constante.

Extrait du fichier stdio.h sur IBM/RS6000

#define _NIOBRW         20
extern FILE     _iob[_NIOBRW];

#define stdin           (&_iob[0])
#define stdout          (&_iob[1])
#define stderr          (&_iob[2])
     

Retour dbut .

9.2.1 - Fonctions d'ouverture et de fermeture

L'acquisition d'un nouveau flot s'effectue par l'appel la fonction fopen. La fonction fclose permet de le fermer.

Syntaxe

FILE *fopen(const char *file, const char *type);
int   fclose(const FILE *flot);
     

La fonction fopen retourne un pointeur sur le 1er lment libre du vecteur _iob s'il en existe, sinon sur une zone de type FILE alloue dynamiquement.

Un pointeur NULL, pseudo-constante dfinie comme (void *)0 dans stdio.h, indique une fin anormale.

La fonction fclose retourne 0 en cas de succs, -1 sinon.

Le 2e argument de la fonction fopen indique le mode d'ouverture du fichier.

Accs Paramtre Position Comportement
si le fichier
existe
si le fichier
n'existe pas
lecture r dbut .erreur
criture w
a
dbut
fin
mis zro cration
cration
lecture
et
criture
r+
w+
a+
dbut
dbut
fin
mis zro erreur
cration
cration

Certains systmes font la distinction entre les fichiers texte et binaire. Pour manipuler ces derniers, il suffit de rajouter le caractre b dans la chane indiquant le mode d'ouverture. Sous UNIX, il est ignor car il n'existe aucune diffrence entre un fichier binaire et un fichier de donnes quelconques.

Exemple

#include <stdio.h>
main()
{
   FILE * flot;

   if ((flot = fopen("donnees", "r")) == NULL) {
     fprintf(stderr, "Erreur a l'ouverture\n");
     exit(1);
   }
       ...
       ...
   fclose(flot);
}
  

Retour dbut .

9.2.2 - Lecture et criture par caractre

Les fonctions getc, fgetc et putc, fputc permettent de lire ou crire un caractre sur un flot donn.

getc et putc sont des pseudo-fonctions.

Syntaxe

  int getc(FILE *Stream)
  int fgetc(FILE *Stream)
  int putc(int c, FILE *Stream)
  int fputc(int c, FILE *Stream)
  

Il existe deux pseudo-fonctions supplmentaires :

Ces fonctions retournent soit le caractre trait, soit la pseudo-constante EOF, dfinie comme -1 dans le fichier stdio.h, en cas d'erreur (fin de fichier par exemple).

Deux pseudo-fonctions feof et ferror, dfinies dans le fichier stdio.h, permettent de tester, respectivement, la fin de fichier et une ventuelle erreur d'entre-sortie sur le flot pass en argument.

Dans le cas d'une entre-sortie au terminal, c'est le retour chariot qui provoque l'envoi au programme de la mmoire tampon rattache au pilote /dev/tty.

Exemple

#include <stdio.h>
main()
{
  char c;  <=== Attention Erreur !
                ----------------

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

Exemples corrects

#include <stdio.h>
main()
{
  int c;

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

#include <stdio.h>
main()
{
  int c;

  c = getchar();
  while (!ferror(stdin) &&
         !feof(stdin)) {
     putchar(c);
     c = getchar();
  }
}
  

Retour dbut .

9.2.3 - Lecture et criture de mots

Les fonctions getw et putw permettent de lire ou crire des mots.

Syntaxe

  int getw(FILE *flot)
  int putw(int c, FILE *flot)
  

Exemple

#include <stdio.h>
#define DIM 100
main()
{
   FILE *flot;
   int   tab[DIM];
   int   i;

   if ((flot = fopen("resultat", "w")) == NULL) {
     perror("fopen");
     exit(1);
   }
   for (i=0; i < DIM; i++) {
      tab[i] = i*i;
      putw(tab[i], flot);
   }
   fclose(flot);
}
  

Retour dbut .

9.2.4 - Lecture et criture d'une chane de caractres

Les fonctions gets, fgets et puts, fputs permettent de lire et crire des chanes de caractres.

Syntaxe

  char *gets(char *string)
  int   puts(char *string)
  char *fgets(char *string, int nombre, FILE *flot)
  int   fputs(char *string, FILE *flot)
  


Les fonctions gets, fgets renvoient la chane lue ou le pointeur NULL si fin de fichier. Les fonctions puts, fputs renvoient le nombre de caractres crits ou EOF si erreur.

Exemple

#include <stdio.h>
main()
{
  char *mus1 = "Wolfgang Amadeus Mozart\n";
  char *mus2 = "Ludwig van Beethoven\n";
  char  buffer[BUFSIZ+1];
  FILE *f;
  if ((f = fopen("musiciens", "w")) == NULL) {
    perror("fopen");
    exit(1);
  }
  fputs(mus1, f); fputs(mus2, f);
  fclose(f);
  if ((f = fopen("musiciens", "r")) == NULL) {
    perror("fopen");
    exit(2);
  }
  while (fgets(buffer, sizeof(buffer), f))
     fputs(buffer, stdout);
  fclose(f);
  puts("\nExecution terminee.");
}
  

Retour dbut .

9.2.5 - Lecture et criture de blocs

Les fonctions fread et fwrite permettent de lire et d'crire des blocs de donnes tels des structures ou des tableaux.

Syntaxe

size_t fread(void *p, size_t t, size_t n, FILE *f)
size_t fwrite(void *p, size_t t, size_t n, FILE *f)
  
Ces fonctions retournent le nombre de blocs traits. Utiliser les pseudo-fonctions feof et ferror pour tester la fin de fichier et une erreur d'entre-sortie.

Exemple

#include <stdio.h>
#define NbElt(t) ( sizeof t / sizeof t[0] )
main() {
  typedef struct { int   n; float t[10]; char  c;
                 } DONNEE;
  DONNEE s1   = { 1, { 1.,  2., 3.}, 'a'};
  DONNEE s2[] = { {4, {10., 32., 3.}, 'z'},
                  {5, { 2., 11., 2., 4.}, 'h'} };
  FILE *f, *f_sauve; DONNEE s;
  if ((f = fopen("donnee", "w")) == NULL)
    perror("fopen"), exit(1);
  fwrite(&s1, sizeof(DONNEE), 1, f);
  fwrite( s2, sizeof(DONNEE), NbElt(s2), f);
  fclose(f);
  if ((f = fopen("donnee", "r")) == NULL ||
      (f_sauve = fopen("sauvegarde", "w")) == NULL)
    perror("fopen"), exit(2);
  fread(&s, sizeof(DONNEE), 1, f);
  while (!feof(f)) {
    fwrite(&s, sizeof(DONNEE), 1, f_sauve);
    fread(&s, sizeof(DONNEE), 1, f); }
  fclose(f); fclose(f_sauve);
}
  

Retour dbut .

9.2.6 - Accs direct

Par dfaut, les fonctions prcdentes travaillent en mode squentiel. Chaque lecture ou criture s'effectue partir d'une position courante, et incrmente cette position du nombre de caractres lus ou crits.

Les fonctions fseek et ftell permettent, respectivement, de modifier et rcuprer la position courante.

int  fseek(FILE *f, long decalage, int position);
long ftell(FILE *f);
    

La fonction ftell retourne la position courante en octets.

La fonction fseek permet de la modifier :

Exemple

#include <stdio.h>
main(int argc, char **argv)
{
   FILE *f;
   void  usage(char *s);

   if (argc != 2)
     usage(argv[0]);
   if ((f = fopen(argv[1], "r")) == NULL) {
     perror("fopen");
     exit(2);
   }
   fseek(f, 0L, SEEK_END);
   printf("Taille(octets) : %d\n", ftell(f));
   fclose(f);
}

void  usage(char *s)
{
   fprintf(stderr, "usage : %s fichier\n", s);
   exit(1);
}
     

Retour dbut .

9.2.7 - Entres-sorties formates

Les fonctions scanf, fscanf, sscanf et printf, fprintf, sprintf permettent d'effectuer des entres-sorties de donnes avec conversions.

Syntaxe

int scanf(const char *format [, ...])
int fscanf(FILE *f, const char *format [, ...])
int sscanf(const char *buffer,
           const char *format [, ...])
int printf(const char *format [, ...])
int fprintf(FILE *f, const char *format [, ...])
int sprintf(const char *buffer,
            const char *format [, ...])
  

Fonctions printf, fprintf, sprintf

Le paramtre format dsigne une chane de caractres comprenant :

Aprs les conversions effectues, cette chane est reproduite : Les spcifications de conversions portent successivement sur les arguments passs la suite du paramtre format.

Une spcification de conversion est constitue du caractre %, suivie dans l'ordre :

Exemples

printf("|%d|\n", 1234);             |1234|
printf("|%-d|\n", 1234);            |1234|
printf("|%+d|\n", 1234);            |+1234|
printf("|% d|\n", 1234);            | 1234|
printf("|%10d|\n", 1234);           |      1234|
printf("|%10.6d|\n", 1234);         |    001234|
printf("|%10.2d|\n", 1234);         |      1234|
printf("|%.6d|\n", 1234);           |001234|
printf("|%06d|\n", 1234);           |001234|
printf("|%.2d|\n", 1234);           |1234|
printf("|%*.6d|\n", 10, 1234);      |    001234|
printf("|%*.*d|\n", 10, 6, 1234);   |    001234|
printf("|%x|\n", 0x56ab);           |56ab|
printf("|%#x|\n", 0x56ab);          |0x56ab|
printf("|%X|\n", 0x56ab);           |56AB|
printf("|%#X|\n", 0x56ab);          |0X56AB|
  
printf("|%f|\n",1.234567890123456789e5);
               |123456.789012|
printf("|%.4f|\n",1.234567890123456789e5);
               |123456.7890|
printf("|%.15f|\n",1.234567890123456789e5);
               |123456.789012345670000|
printf("|%15.4f|\n",1.234567890123456789e5);
               |    123456.7890|

printf("|%e|\n",1.234567890123456789e5);
               |1.234568e+05|
printf("|%.4e|\n",1.234567890123456789e5);
               |1.2346e+05|
printf("|%.18e|\n",1.234567890123456789e5);
               |1.234567890123456700e+05|
printf("|%18.4e|\n",1.234567890123456789e5);
               |        1.2346e+05|
printf("|%.4g|\n",1.234567890123456789e-5);
               |1.235e-05|
printf("|%.4g|\n",1.234567890123456789e+5);
               |1.235e+05|
printf("|%.4g|\n",1.234567890123456789e-3);
               |0.001235|
printf("|%.8g|\n",1.234567890123456789e5);
               |123456.79|
  
#include <stdio.h>
main()
{
  char *chaine = "Wolfgang Amadeus Mozart";

  printf("|%s|\n", chaine);      ===> 1)
  printf("|%.16s|\n", chaine);   ===> 2)
  printf("|-23.16s|\n", chaine); ===> 3)
  printf("|23.16s|\n", chaine);  ===> 4)
}

  1) |Wolfgang Amadeus Mozart|

  2) |Wolfgang Amadeus|

  3) |Wolfgang Amadeus       |

  4) |       Wolfgang Amadeus|

  

Fonctions scanf, fscanf, sscanf

Ces fonctions permettent d'effectuer des entres formates. Les donnes lues sont converties suivant les spcifications de conversions indiques dans la chane format, puis stockes dans les arguments successifs fournis sa suite. Ces arguments doivent tre des pointeurs.

La valeur retourne correspond au nombre d'arguments correctement affects. La chane format peut contenir :

Les donnes en entre sont dcoupes en champs.

Chaque champ est dfini comme une chane de caractres qui s'tend soit :

Une spcification de conversion est constitue du caractre % suivi dans l'ordre :

Remarques

Les arguments correspondant aux spcifications :

On peut faire prcder les spcifications d, i, o, x, u par la lettre h ou l pour rfrencer un short * ou un long *.

De mme les spcifications e, f, g peuvent tre prcdes de la lettre l pour rfrencer un double *.

Exemples

#include <stdio.h>
main()
{
  int   i;
  float x, y;
  char  buffer[BUFSIZ];
  char *p = "12/11/94";
  int   jour, mois, annee;

  scanf("%d%f%f%*c", &i, &x, &y);
  printf("i = %d, x = %f, y = %f\n", i, x, y);
  scanf("%[^\n]%*c", buffer);
  while (!feof(stdin)) {
    fprintf(stderr, "%s\n", buffer);
    scanf("%[^\n]%*c", buffer);
  }
  sscanf(p, "%d/%d/%d", &jour, &mois, &annee);
  printf("jour  : %d\n", jour);
  printf("mois  : %d\n", mois);
  printf("annee : %d\n", annee);
}
  
#include <stdio.h>
main()
{
  char   mois[10], buffer[BUFSIZ];
  int    quantite;
  double prix;
  FILE  *f;
  if ((f=fopen("donnees", "r")) == NULL)
    perror("fopen"), exit(1);
  fgets(buffer, sizeof(buffer), f);
  while (!feof(f)) {
    sscanf(buffer, "%s%d%lf",
            mois, &quantite, &prix);
    printf("mois : %s, qte : %d, prix : %f\n",
            mois, quantite, prix);
    fgets(buffer, sizeof(buffer), f);
  }
  fseek(f, 0L, SEEK_SET);
  fscanf(f, "%s%d%lf", mois, &quantite, &prix);
  while (!feof(f)) {
    printf("mois : %s, qte : %d, prix : %f\n",
            mois, quantite, prix);
    fscanf(f, "%s%d%lf", mois, &quantite, &prix);
  }
  fclose(f);
}
  

Retour dbut .

9.2.8 - Autres fonctions

La fonction freopen permet de redfinir un flot dj initialis. Elle est principalement utilise avec les flots stdin, stdout, stderr, ce qui correspond une redirection d'entres-sorties.

La fonction fflush permet de forcer le vidage de la mmoire tampon associe un flot en sortie. Sur un flot en entre l'effet est imprvisible.

Syntaxe

FILE *freopen(char *fichier, char *mode, FILE *flot);
int   fflush(FILE *flot);
    

Exemple

#include <stdio.h>
main(int argc, char **argv)
{
  void usage(char *s);

  if (argc != 2)
    usage(argv[0]);
  if (freopen(argv[1], "w", stdout) == NULL) {
    perror("freopen");
    exit(2);
  }
  printf("Ce message est redirige ");
  printf("dans le fichier ");
  printf("dont le nom est ");
  printf("passe en argument.\n");
}

void usage(char *s)
{
  fprintf(stderr, "usage : %s fichier\n", s);
  exit(1);
}
    

Retour dbut .

9.3 - Manipulation de caractres


Le fichier en-tte ctype.h contient des dclarations de fonctions permettant de tester les caractres. Elles admettent un argument de type entier et retourne un entier :

Les caractres imprimables sont compris entre 0x20 et 0x7e, les caractres de contrle sont compris entre 0 et 0x1f ainsi que 0x7f.

Il existe, de plus, deux fonctions permettant de convertir les majuscules en minuscules et rciproquement :

Exemple

#include <stdio.h>
#include <ctype.h>
main()
{
   int c;
   int NbMaj = 0;
   int NbMin = 0;
   int NbNum = 0;
   int NbAutres = 0;
   while((c=getchar()) != EOF)
      if (isupper(c))
        NbMaj++;
      else if (islower(c))
        NbMin++;
      else if (isdigit(c))
        NbNum++;
      else
        NbAutres++;
   printf("NbMaj    : %d\n", NbMaj);
   printf("NbMin    : %d\n", NbMin);
   printf("NbNum    : %d\n", NbNum);
   printf("NbAutres : %d\n", NbAutres);
}
     

Retour dbut .

9.4 - Fonctions de conversions


Le fichier en-tte stdlib.h contient des dclarations de fonctions permettant la conversion de donnes de type chane de caractres en donnes numriques :

Exemple

#include <stdio.h>
#include <stdlib.h>
main()
{
  char   *s = "     37.657654";
  double  d;
  long    l;

  d = strtod(s, NULL);
  printf("d : %f\n", d);            ===> 37.657654
  s = "11001110101110";
  l = strtol(s, NULL, 2);
  printf("%ld\n", l);               ===> 13230
  s = "0x7fff";
  l = strtol(s, NULL, 0);
  printf("%ld\n", l);               ===> 32767
  s = "0777";
  l = strtol(s, NULL, 0);
  printf("%ld\n", l);               ===>   511
  s = "777";
  l = strtol(s, NULL, 0);
  printf("%ld\n", l);               ===>   777
}
     

Retour dbut .

9.5 - Manipulation de chanes de caractres


Le fichier en-tte string.h contient des dclarations de fonctions permettant la manipulation de chanes de caractres :

Le type size_t est un alias du type unsigned long.

Exemple

#include <stdio.h>
#include <string.h>
main(int argc, char **argv)
{
   char *parm1, *parm2, buffer[BUFSIZ];
   if (argc != 3) usage(argv[0]);
   parm1 = strdup(argv[1]);
   parm2 = strdup(argv[2]);
   strcat(strcpy(buffer, "Resultat de la "
                         "concatenation : "),
          parm1);
   strcat(strcat(buffer, parm2), "\n");
   printf("%s", buffer);
   sprintf(buffer, "%s%s%s\n", "Resultat de la "
                               "concatenation : ",
                                parm1, parm2);
   printf("%s", buffer);
   free(parm1); free(parm2);
}
void usage (char *s) {
   fprintf(stderr, "usage : %s ch1 ch2.\n", s);
   exit(1);
}
      

Exemple

#include <stdio.h>
#include <string.h>
main(int argc, char **argv)
{
   void usage (char *s);
   char *s  = "/usr/include/string.h", *p;
   int   NbSlash = 0;
   if (argc != 3) usage(argv[0]);
   if (!strcmp(argv[1], argv[2]))
     printf("Les 2 arguments sont identiques.\n");
   else if (strcmp(argv[1], argv[2]) > 0)
       printf("arg1 > arg2\n");
   else printf("arg1 < arg2\n");
   for (p = s-1; p = strchr(++p, '/'); NbSlash++)
              ;
   printf("La chaine s contient %d\n", NbSlash);
   printf("slashs sur %d caracteres.\n", strlen(s));
}
void usage (char *s)
{
   fprintf(stderr, "usage : %s ch1 ch2.\n", s);
   exit(1);
}
      

Il existe d'autres fonctions qui agissent sur des tableaux de caractres plutt que des chanes de caractres :

Exemple

#include <stdio.h>
#include <string.h>
main()
{
   char  buffer[100];
   char  tab[] = "Voici\0une chaine qui"
                 "\0\0contient\0des"
                 "\0caracteres \"null\".";
   char *p, *ptr;
   int   taille = sizeof tab / sizeof tab[0];
   int   n;

   memset(buffer, ' ', 100);
   n = --taille;
   for (p=ptr=tab; p=memchr(ptr, '\0', n);)
   {
      *p = ' ';
      n -= p - ptr + 1;
      ptr = ++p;
   }
   printf("%s\n", tab);
   printf("%.*s\n", taille, tab);
}
      

Retour dbut .

9.6 - Allocation dynamique de mmoire


Les fonctions permettant de faire de l'allocation dynamique de mmoire sont :