Vous êtes sur la page 1sur 39

Introduction langage C

Jean-Franois Pillou 2003

1 Introduction
1.1 Petite histoire du C
Le langage C a t mis au point par D.Ritchie et B.W.Kernighan au dbut des annes 70. Leur but tait de permettre de dvelopper un langage qui permettrait dobtenir un systme dexploitation de type UNIX portable. D.Ritchie et B.W.Kernighan se sont inspirs des langages B et BCPL, pour crer un nouveau langage: le langage C. La premire dnition de ce langage a t donne dans leur livre commun "The C programming language". Toutefois, suite lapparition de nombreux compilateurs C, lANSI (abrviation de American National Standards Institute) a dcid de normaliser ce langage pour donner ce que lon appelle le C-ANSI. Suite cette norme, Ritchie et Kernighan ont sorti une deuxime dition du livre en intgrant les modications apportes par lANSI.

1.2 Les atouts du C


Le langage C reste un des langages les plus utiliss actuellement. Cela est d au fait que le langage C est un langage comportant des instructions et des structures de haut niveau (contrairement lassembleur par exemple) tout en gnrant un code trs rapide grce un compilateur trs performant. Un des principaux intrts du C est que cest un langage trs portable. Un programme crit en C en respectant la norme ANSI est portable sans modications sur nimporte quel systme dexploitation disposant dun compilateur C : Windows, UNIX, VMS (systme des VAX) ou encore OS/390 ou z/Os (lOS des mainframes IBM). La rapidit des programmes crits en C est en grande partie due au fait que le compilateur prsuppose que le programmeur sait ce quil fait: il gnre un code ne contenant pas de vrications sur la validit des pointeurs, lespace dadressage, etc. Ainsi, les programmes en C sont trs compacts. De plus, une des caractristiques du C est quil est un langage "faiblement typ" : les types de donnes quil manipule sont trs restreints, et proches de la reprsentation interne par le processeur : par exemple, le type Chane de caractres nexiste pas en C. A linverse, comparer un entier et un caractre a un sens en C car un caractre est bien reprsent en interne par le processeur par une valeur de type entier (le code ASCII ou le code EBCDIC). Enn et pour conclure, il est inexact que le C est un langage difcile apprendre! Au contraire: Le C dispose de peu dinstructions, les structures de donnes sont limites, etc. Le C est un langage concis et son apprentissage est beaucoup moins ardu que ne peut ltre celui du Pascal par exemple; Lapprentissage du C est ainsi ncessaire pour quiconque sintresse la programmation, et cet apprentissage en vaut la peine !

1.3 Le C++ par rapport au C


Le C++ est un langage bas sur le langage C, auquel on a rajout des lments de telle manire intgrer le concept objet. Cest Bjarne Stroustrup qui a cr la premire version de ce langage, appel C++.
Voir http://www.commentcamarche.net/c/cintro.php3, c Copyright 2003 Jean-Franois Pillou - Hberg par Websolutions.fr. Ce document issu de CommentCaMarche.net est soumis la licence GNU FDL. Vous pouvez copier, modier des copies de cette page tant que cette note apparat clairement.

2 Caractristiques du langage C
2.1 Le chier source
Le chier source dun programme crit en langage C est un simple chier texte dont lextension est par convention .c1 . Ce chier source doit tre un chier texte non format, cest--dire un chier texte dans sa plus simple expression, sans mise en forme particulire ou caractres spciaux (il contient uniquement les caractres ASCII de base). Lorsque le programme est prt tre "essay", il sagit de le compiler (le traduire en langage machine). De nombreux compilateurs C existent: sous les systmes de type UNIX par exemple, le compilateur C est fourni en standard, si bien que la programmation en langage C est aise sous ce type de systme. La compilation sous UNIX se fait par la ligne de commande suivante:
cc fichier.c

2.2

Aspect dun programme en C

Un programme crit en langage C, comporte une fonction principale appele main() renfermant les instructions qui doivent tre excutes. Celles-ci sont comprises entre des accolades qui suivent le nom de la fonction. Cela vous semble tomb du ciel si vous navez jamais programm en C, mais il faut admettre pour linstant la manire dcrire un programme en C. La nalit de cette criture vous sera dvoile au cours des chapitres suivants... Un programme C de base ressemblera donc ceci :
main() { printf("Ceci est votre premier programme"); }

Le programme prsent ci-dessus contient donc une fonction principale main() (qui, rappelons-le, est essentielle car cest par cette fonction que le programme sexcute) contenant une instruction imprimant lcran le message "Ceci est votre premier programme" grce la fonction printf(). Remarques

Le type retourn par main() est int. La norme actuelle du C (C99) impose que le type soit explicite, il faut donc crire :
int main()

Il est recommand de dnir une fonction sous sa forme prototype. Dans ce cas, main() nayant pas de paramtres, on lindique avec void.
int main(void)

1 Lextension est en minuscules. Le .C (majuscule) est interprt par certains compilateurs comme lextension du C++ (gcc). Comme il existe de petites diffrences entre la compilation dun programme en C et la compilation de ce mme programme en C++, cela peut parfois poser des problmes.

printf() est une fonction avec nombre variable de paramtres. Il est obligatoire de fournir un prototype cette fonction. Il manque par exemple:
#include <stdio.h>

printf() produit une mission de caractres en squence vers stdout. Certaines implmentations de stdout tant buffrises, il est recommand de terminer la chaine mise par un \n, ce qui dclenche lmission effective. Sinon, il est possible de la forcer avec fush(stdout) :
printf ("Ceci est votre premier programme\n");

Bien que la norme actuelle (C99) autorise main() ne pas avoir de return explicite (dans ce cas on a un return 0 implicite), cette pratique est peu recommande pour des questions de compatibilit avec la norme courante (C90) qui exige quune fonction retournant autre chose que void ait un return quelque chose explicite.
#include <stdio.h> int main (void) { printf ("Ceci est votre premier programme\n"); return 0; }

2.3 Typologie
La manire dcrire les choses en langage C a son importance. Le langage C est par exemple sensible la casse (en anglais case sensitive), cela signie quun nom contenant des majuscules est diffrent du mme nom crit en minuscules. Ainsi, les spcications du langage C prcisent que la fonction principale doit tre appele main() et non Main() ou MAIN(). De la mme faon, on remarquera que la fonction printf() est crite en minuscules. Dautre part, linstruction printf() se termine par un point-virgule. Ce dtail a son importance, car en langage C, toute instruction se termine par un point-virgule.

2.4 Ajout de commentaires


Lorsquun programme devient long et compliqu, il peut tre intressant (il est mme conseill) dajouter des lignes de commentaires dans le programme, cest--dire des portions du chier source qui ont pour but dexpliquer le fonctionnement du programme sans que le compilateur ne les prenne en compte (car il gnrerait une erreur). Pour ce faire, il faut utiliser des balises qui vont permettre de dlimiter les explications an que le compilateur les ignore et passe directement la suite du chier. Ces dlimiteurs sont /* et */. Un commentaire sera donc not de la faon suivante:
/*Voici un commentaire!*/

En plus des symboles /* et */, fonctionant un peu comme des parenthses, le symbole // permet de mettre en commentaire toute la ligne qui la suit (i.e. les caractres droite de ce symbole sur la mme ligne.

Il convient toutefois dutiliser prfrablement la notation /**/ que //, car cest beaucoup plus joli et plus propre. La notation // est gnralement rserve pour mettre en commentaire une ligne de code que lon ne veut dsactiver temporairement. Il y a toutefois quelques rgles respecter:

Les commentaires peuvent tre placs nimporte o dans le chier source ;

Les commentaires ne peuvent contenir le dlimiteur de n de commentaire (*/) ;

Les commentaires ne peuvent tre imbriqus ;

Les commentaires peuvent tre crits sur plusieurs lignes ;

Les commentaires ne peuvent pas couper un mot du programme en deux.

3 Notion de prprocesseur
3.1 Dnition du prprocesseur
Dans les chapitres prcdents, un programme simple vous a t prsent, il sagit du programme suivant:
int main(void) { printf("Ceci est votre premier programme"); }

Dans ce programme la fonction principale main() contient une fonction appele printf() qui a pour but dafcher le message "Ceci est votre premier programme". En ralit le compilateur ne connait pas la fonction printf() bien quil sagisse dune fonction standard du langage C. Cette fonction est effectivement stocke dans un chier annexe, contenant une librairie de fonctions, appel chier de dnition (ventuellement chier den-tte ou chier header), dont lextension est .h. Il sagit donc de prciser au compilateur dans quel chier se trouve la dnition de la fonction printf()... Celle-ci se trouve dans le chier den-tte appel stdio.h. La dsignation stdio signie Standard Input Output (en franais Entres Sorties standards), cest--dire que ce chier contient la dnition de nombreuses fonctions permettant lentre (saisie au clavier, ...) et la sortie (afchage, sortie dans un chier, ...) de donnes, dont la fonction printf() fait partie. Lincorporation de la dclaration de la fonction printf() se fait au moyen de linstruction #include (que lon place en dbut de chier) suivie des balises < et > contenant le nom de chier contenant la dnition de la fonction. La dclaration include doit se trouver avant toute utilisation des mthodes dclares, sinon le compilateur gnrera au minimum un warning. Le programme ci-dessus pour pouvoir tre compil doit donc scrire:
#include <stdio.h> int main(void) { printf("Ceci est votre premier programme"); }

Le chier est maintenant apte tre compil. Il existe dautres commandes du prprocesseur qui seront dtailles dans ce cours 2 .

3.2 Phases de compilation


La compilation se fait gnralement en plusieurs phases:

le compilateur transforme le code source en code objet, et le sauvegarde dans un chier objet, cest--dire quil traduit le chier source en langage machine (certains compilateurs crent aussi un chier en assembleur, un langage proche du langage machine car possdant des fonctions trs simples, mais lisible) ;
instructions ddies au prprocesseur ne se terminent pas par un point-virgule!

2 Les

le compilateur fait ensuite appel un diteur de liens (en anglais linker ou binder) qui permet dintgrer dans le chier nal tous les lments annexes (fonctions ou librairies) auquel le programme fait rfrence mais qui ne sont pas stocks dans le chier source ;

Dans le cas du langage C, une phase supplmentaire apparat, il sagit du traitement du chier par le prprocesseur C, un programme permet dinclure dans le chier source les lments rfrencs par les instructions situes au dbut du chier source (instructions prcdes du caractre #). Cest donc le prprocesseur qui ajoutera dans le chier source la dnition de la fonction printf() quil sera all chercher dans le chier stdio.h grce linstruction #include. Les phases de compilation dans le cas dun compilateur C sont donc les suivantes:

4 Types de donnes
4.1 Les types de donnes
Les donnes manipules en langage C sont types, cest--dire que pour chaque donne que lon utilise (dans les variables par exemple) il faut prciser le type de donne, ce qui permet de connatre loccupation mmoire (le nombre doctets) de la donne ainsi que sa reprsentation

des nombres: entiers (int) ou rels, cest--dire virgules (oat) ; des pointeurs (pointer): permettent de stocker ladresse dune autre donne, ils "pointent" vers une autre donne ;
En C il existe plusieurs types entiers, dpendant du nombre doctets sur lesquels ils sont cods ainsi que de leur format, cest--dire si ils sont signs (possdant le signe - ou +) ou non. Par dfaut les donnes sont signes. Voici un tableau donnant les types de donnes en langage C: Type de donne char unsigned char short int unsigned short int int int unsigned int unsigned int long int unsigned long int oat double long double Signication Caractre Caractre non sign Entier court Entier court non sign Entier Entier Entier non sign Entier non sign Entier long Entier long non sign ottant (rel) ottant double ottant double long Taille (en octets) 1 1 2 2 2 (sur processeur 16 bits) 4 (sur processeur 32 bits) 2 (sur processeur 16 bits) 4 (sur processeur 32 bits) 4 2 4 8 10 Plage de valeurs accepte -128 127 0 255 -32768 32767 0 65535 -32768 32767 -2147483647 2147483647 0 65535 0 4294967295 -2 147 483 648 2 147 483 647 0 4 294 967 295    !" #!"$ % &')( 0&)'$)(

4.2 Nombre entier (int)


Un nombre entier est un nombre sans virgule qui peut tre exprim dans diffrentes bases:

Base dcimale: Lentier est reprsent par une suite de chiffre unitaires (de 0 9) ne devant pas commencer par
le chiffre 0 ;

Base hexadcimale: Lentier est reprsent par une suite dunits (de 0 9 ou de A F (ou a f)) devant
commencer par 0x ou 0X ;

Base octale: Lentier est reprsent par une suite dunits (incluant uniquement des chiffres de 0 7) devant
commencer par 0. Les entiers sont signs par dfaut, cela signie quils comportent un signe. Pour stocker linformation concernant le signe (en binaire), les ordinateurs utilisent le complment deux.

4.3 Nombre virgule (oat)


Un nombre virgule ottante est un nombre virgule, il peut toutefois tre reprsent de diffrentes faons:

un entier dcimal: 1203

un nombre comportant un point (et non une virgule): 1 3 4


7

une fraction: un nombre exponentiel, cest--dire un nombre (ventuellement virgule) suivi de la lettre e (ou E), puis dun  entier correspondant la puissance de 10 (sign ou non, cest--dire prcd dun + ou dun -) :  !#" $%
En ralit, les nombres rels sont des nombres virgule ottante, cest--dire un nombre dans lequel la position de la virgule nest pas xe, et est repre par une partie de ses bits (appele lexposant), le reste des bits permettent de coder le nombre sans virgule (la mantisse). Les nombres de type oat sont cods sur 32 bits dont:

23 bits pour la mantisse ; 8 bits pour lexposant ; 1 bit pour le signe.


Les nombres de type double sont cods sur 64 bits dont:

52 bits pour la mantisse ; 11 bits pour lexposant ; 1 bit pour le signe.


Les nombres de type long double sont cods sur 80 bits dont:

64 bits pour la mantisse ; 15 bits pour lexposant ; 1 bit pour le signe.


La prcision des nombres rels est approche. Elle dpend par le nombre de positions dcimales, suivant le type de rel elle sera au moins:

de 6 chiffres pour le type oat ; de 15 chiffres pour le type double ; de 17 chiffres pour le type long double.

4.4 Caractre (char)


Le type char (provenant de langlais character) permet de stocker la valeur ASCII dun caractre, cest--dire un nombre entier! Par dfaut les nombres sont signs, cela signie quils comportent un signe. Pour stocker linformation concernant le signe (en binaire), les ordinateurs utilisent le complment deux. Une donne de type char est donc signe, cela ne signie bien sr pas que la lettre possde un signe mais tout simplement que dans la mmoire la valeur codant le caractre peut-tre ngative... Si jamais on dsire par exemple stocker la lettre B (son code ASCII est 66), on pourra dnir cette donne soit par le nombre 66, soit en notant B ou les apostrophes simples signient code ascii de... Il nexiste pas de type de donnes pour les chanes de caractres (suite de caractre) en langage C. Pour crer une chane de caractre on utilisera donc des tableaux contenant dans chacune de ses cases un caractre...

4.5 Crer un type de donne


Il est possible en C de dnir un nouveau type de donnes grce au mot cl typedef. Celui-ci admet la syntaxe suivante:
typedef Caracteristiques_du_type Nom_du_type

Caracteristiques_du_type reprsente un type de donnes existant (par exemple float, short int, ...) ;

Nom_du_type dnit le nom que vous donnez au nouveau type de donne.

Ainsi linstruction suivante cre un type de donne Ch calqu sur le type char
typedef char Ch

4.6 Conversion de type de donnes


On appelle conversion de type de donnes le fait de modier le type dune donne en une autre. Il peut arriver par exemple que lon veuille travailler sur un type de variable, puis lutiliser sous un autre type. Imaginons que lon travaille par exemple sur une variable en virgule ottante (type oat), il se peut que lon veuille "supprimer les chiffres aprs la virgule", cest--dire convertir un oat en int. Cette opration peut tre ralise de deux manires:

conversion implicite: une conversion implicite consiste en une modication du type de donne effectue automatiquement par le compilateur. Cela signie que lorsque lon va stocker un type de donne dans une variable dclare avec un autre type, le compilateur ne retournera pas derreur mais effectuera une conversion implicite de la donne avant de laffecter la variable.
int x; x = 8.324;

x contiendra aprs affectation la valeur 8

conversion explicite: une conversion explicite (appele aussi opration de cast) consiste en une modication du type de donne force. Cela signie que lon utilise un oprateur dit de cast pour spcier la conversion. Loprateur de cast est tout simplement le type de donne, dans lequel on dsire convertir une variable, entre des parenthses prcdant la variable.
int x; x = (int)8.324;

x contiendra aprs affectation la valeur 8

5 Les variables du langage C


5.1 Le concept de variable
Une variable est un objet repr par son nom, pouvant contenir des donnes, qui pourront tre modies lors de lexcution du programme. Les variables en langage C sont types, cest--dire que les donnes contenues dans celles-ci possdent un type, ainsi elles sont donc stockes dans la mmoire et occupent un nombre doctets dpendant du type de donne stocke. En langage C, les noms de variables peuvent tre aussi long que lon dsire, toutefois le compilateur ne tiendra compte que des 32 premiers caractres. De plus, elles doivent rpondre certains critres:

un nom de variable doit commencer par une lettre (majuscule ou minuscule) ou un "_" (pas par un chiffre) ;

un nom de variables peut comporter des lettres, des chiffres et le caractre "_" (les espaces ne sont pas autoriss!) ;

Les noms de variables ne peuvent pas tre les noms suivants (qui sont des noms rservs):
auto break case char const continue default do double else enum extern float for goto if, int long register, return short, signed, sizeof, static, struct, switch typedef union, unsigned void, volatile while

Nom de variable correct Variable Nom_De_Variable nom_de_variable nom_de_variable_123 _707

Nom de variable incorrect Nom de Variable 123Nom_De_Variable toto@mailcity.com Nom-de-variable goto

Raison comporte des espaces commence par un chiffre caractre spcial @ signe - interdit nom rserv

Les noms de variables sont sensibles la casse (le langage C fait la diffrence entre un nom en majuscule et un nom en minuscules), il faut donc veiller utiliser des noms comportant la mme casse!

5.2 La dclaration de variables


Pour pouvoir utiliser une variable, il faut la dnir, cest--dire lui donner un nom, mais surtout un type de donne stocker an quun espace mmoire conforme au type de donne quelle contient lui soit rserv. Une variable se dclare de la faon suivante:
type Nom_de_la_variable;

ou bien sil y a plusieurs variables du mme type:


type Nom_de_la_variable1, Nom_de_la_variable2, ...;

5.3 Affectation dune donne une variable


Pour stocker une donne dans une variable que lon a initialise, il faut faire une affectation, cest--dire prciser la donne qui va tre stocke lemplacement mmoire qui a t rserv lors de linitialisation. 10

Pour cela on utilise loprateur daffectation "=" :


Nom_de_la_variable = donne;

Pour stocker le caractre B dans la variable que lon a appele Caractere, il faudra crire:
Caractere = B;

Ce qui signie stocker la valeur ASCII de "B" dans la variable nomme "Caractere". Il est bien vident quil faut avoir pralablement dclar la variable en lui affectant le type char:
char Caractere;

5.4 Initialisation dune variable


La dclaration dune variable ne fait que "rserver" un emplacement mmoire o stocker la variable. Tant que lon ne lui a pas affect une donne celle-ci contient ce qui se trouvait prcdemment cet emplacement, que lon appelle garbage (en franais: dtritus). On peut donc affecter une valeur initiale la variable lors de sa dclaration, on parle alors dinitialisation:
type Nom_de_la_variable = donnee;

Par exemple:
float Toto = 125.36;

5.5 Porte (visibilit) des variables


Selon lendroit o on dclare une variable, celle-ci pourra tre accessible (visible) de partout dans le code ou bien que dans une portion conne de celui-ci ( lintrieur dune fonction par exemple), on parle de porte (ou visibilit) dune variable. Lorsquune variable est dclare dans le code mme, cest--dire lextrieur de toute fonction ou de tout bloc dinstruction, elle est accessible de partout dans le code (nimporte quelle fonction du programme peut faire appel cette variable). On parle alors de variable globale Lorsque lon dclare une variable lintrieur dun bloc dinstructions (entre des accolades), sa porte se conne lintrieur du bloc dans lequel elle est dclare.

Une variable dclare au dbut du code, cest--dire avant tout bloc de donne, sera globale, on pourra alors les utiliser partir de nimporte quel bloc dinstruction

Une variable dclare lintrieur dun bloc dinstructions (dans une fonction ou une boucle par exemple) aura une porte limite ce seul bloc dinstruction, cest--dire quelle est inutilisable ailleurs, on parle alors de variable locale

5.6 Dnition de constantes


Une constante est une variable dont la valeur est inchangeable lors de lexcution dun programme. En langage C, les constantes sont dnies grce la directive du prprocesseur #define, qui permet de remplacer toutes les 11

occurrences du mot qui le suit par la valeur immdiatement derrire elle. Par exemple la directive:
#define _Pi 3.1415927

remplacera tous les identiants "_Pi" (sans les guillemets) par la valeur 3.1415927, sauf dans les chanes de caractres:
resultat = _Pi * sin(a); //-> remplac resultat = _Pi+1; //-> remplac _Pi = 12; //-> remplac MAIS gnre une erreur resultat = _PiPo; //-> pas remplac printf("pi = _Pi "); //-> pas remplac

Toutefois, avec cette mthode les constantes ne sont pas types, il faut donc utiliser la directive #define avec parcimonie... Il est ainsi prfrable dutiliser le mot clef const, qui permet de dclarer des constantes types :
const int dix = 10;

De plus, cela permet dviter certains problmes du #define, qui fait du "chercher-remplacer" textuel sans rchir.

12

6 Les oprateurs du langage C


6.1 Quest-ce quun oprateur?
Les oprateurs sont des symboles qui permettent de manipuler des variables, cest--dire effectuer des oprations, les valuer, ... On distingue plusieurs types doprateurs:

les oprateurs de calcul

les oprateurs dassignation

les oprateurs dincrmentation

les oprateurs de comparaison

les oprateurs logiques

(les oprateurs bit--bit)

(les oprateurs de rotation de bit)

6.2 Les oprateurs de calcul


Les oprateurs de calcul permettent de modier mathmatiquement la valeur dune variable Oprateur + * / = Dnomination oprateur daddition oprateur de soustraction oprateur de multiplication plus: oprateur de division oprateur daffectation Effet Ajoute deux valeurs Soustrait deux valeurs Multiplie deux valeurs Divise deux valeurs Affecte une valeur une variable Exemple x+3 x-3 x*3 x/3 x=3 Rsultat (avec x valant 7) 10 4 21 2.3333333 Met la valeur 3 dans la variable x

6.3 Les oprateurs dassignation


Ces oprateurs permettent de simplier des oprations telles que ajouter une valeur dans une variable et stocker le rsultat dans la variable. Une telle oprations scrirait habituellement de la faon suivante par exemple: x=x+2. Avec les oprateurs dassignation il est possible dcrire cette opration sous la forme suivante: x+=2. Ainsi, si la valeur de x tait 7 avant opration, elle sera de 9 aprs... Les autres oprateurs du mme type sont les suivants: Oprateur += -= *= /= Effet addition deux valeurs et stocke le rsultat dans la variable ( gauche) soustrait deux valeurs et stocke le rsultat dans la variable multiplie deux valeurs et stocke le rsultat dans la variable divise deux valeurs et stocke le rsultat dans la variable

Notez lutilisation de la fonction ldap_error() sur laquelle nous reviendrons ultrieurement pour afcher les dtails de lerreur ! Loprateur daffectation = renvoie aussi une valeur, qui est celle de la variable aprs affectation. Cela permet notamment de faire des affectations en cascade:
a = b = c = 1;

ce qui correspond : 13

a = (b = (c = 1));

6.4 Les oprateurs dincrmentation


Ce type doprateur permet de facilement augmenter ou diminuer dune unit une variable. Ces oprateurs sont trs utiles pour des structures telles que des boucles, qui ont besoin dun compteur (variable qui augmente de un en un). Un oprateur de type x++ permet de remplacer des notations lourdes telles que x=x+1 ou bien x+=1 Oprateur ++ Dnomination Incrmentation Dcrmentation Effet Augmente dune unit la variable Diminue dune unit la variable Syntaxe x++ x Rsultat (avec x valant 7) 8 6

6.5 Les oprateurs de comparaison


Les oprateurs de comparaisons sont les suivants : Oprateur == A ne pas confondre avec le signe daffectation (=)!! < Dnomination oprateur dgalit Effet Compare deux valeurs et vrie leur galit Exemple x==3 Rsultat (avec x valant 7) Retourne 1 si X est gal 3, sinon 0

oprateur dinfriorit stricte oprateur dinfriorit oprateur de supriorit stricte oprateur de supriorit oprateur frence de dif-

<=

>

>=

!=

Vrie quune variable est strictement infrieure une valeur Vrie quune variable est infrieure ou gale une valeur Vrie quune variable est strictement suprieure une valeur Vrie quune variable est suprieure ou gale une valeur Vrie quune variable est diffrente dune valeur

x<3

Retourne 1 si X est infrieur 3, sinon 0 Retourne 1 si X est infrieur ou gal 3, sinon 0 Retourne 1 si X suprieur 3, sinon 0 est

x<=3

x>3

x>=3

x!=3

Retourne 1 si X est suprieur ou gal 3, sinon 0 Retourne 1 si X est diffrent de 3, sinon 0

6.6 Les oprateurs logiques (boolens)


Ce type doprateur permet de vrier si plusieurs conditions sont vraies: Oprateur || && ! Dnomination OU logique ET logique NON logique Effet Vrie quune des conditions est ralise Vrie que toutes les conditions sont ralises Inverse ltat dune variable boolenne (retourne la valeur 1 si la variable vaut 0, 0 si elle vaut 1) Syntaxe ((condition1)||(condition2)) ((condition1)&&(condition2)) (!condition)

6.7 Les oprateurs bit--bit


Ce type doprateur traite ses oprandes comme des donnes binaires, plutt que des donnes dcimales, hexadcimales ou octales. Ces oprateurs traitent ces donnes selon leur reprsentation binaire mais retournent des valeurs numriques standards dans leur format dorigine. 14

Les oprateurs suivants effectuent des oprations bit--bit, cest--dire avec des bits de mme poids. Oprateur & | Dnomination ET bit--bit OU bit--bit Effet Retourne 1 si les deux bits de mme poids sont 1 Retourne 1 si lun ou lautre des deux bits de mme poids est 1 (ou les deux) Retourne 1 si lun des deux bits de mme poids est 1 (mais pas les deux) Syntaxe 9 & 12 (1001 & 1100) 9 | 12 (1001 | 1100) 9 ^ 12 (1001 ^ 1100) Rsultat(avec x valant 7) 8 (1000) 13 (1101)

OU bit--bit exclusif

5 (0101)

6.8 Les oprateurs de rotation de bit


Ce type doprateur traite ses oprandes comme des donnes binaires dune longueur de 32 bits, plutt que des donnes dcimales, hexadcimales ou octales. Ces oprateurs traitent ces donnes selon leur reprsentation binaire mais retournent des valeurs numriques standards dans leur format dorigine. Les oprateurs suivants effectuent des rotation sur les bits, cest--dire quil dcale chacun des bits dun nombre de bits vers la gauche ou vers la droite. La premire oprande dsigne la donne sur laquelle on va faire le dcalage, la seconde dsigne le nombre de bits duquel elle va tre dcale. Oprateur Dnomination Effet Syntaxe Rsultat (avec x valant 7) 12 (1100)

Rotation gauche

Rotation droite avec conservation du signe

Dcale les bits vers la gauche (multiplie par 2 chaque dcalage). Les zros qui sortent gauche sont perdus, tandis que des zros sont insrs droite Dcale les bits vers la droite (divise par 2 chaque dcalage). Les zros qui sortent droite sont perdus, tandis que le bit non-nul de poids plus fort est recopi gauche

6 1 (110 1)

6 1 (0110 1)

3 (0011)

Les priorits Lorsque lon associe plusieurs oprateurs, il faut que le navigateur sache dans quel ordre les traiter, voici donc dans lordre dcroissant les priorits de tous les oprateurs: Priorit des oprateurs
() * + < == & ^ | && ?: = [] ++ / <= !=

! %

>=

>

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

15

7 Les structures conditionnelles


7.1 Quest-ce quune structure conditionnelle?
On appelle structure conditionnelle les instructions qui permettent de tester si une condition est vraie ou non. Ces structures conditionnelles peuvent tre associes des structures qui se rptent suivant la ralisation de la condition, on appelle ces structures des structures de boucle

7.2 La notion de bloc


Une expression suivie dun point-virgule est appele instruction. Voici un exemple dinstruction :
a++;

Lorsque lon veut regrouper plusieurs instructions, on peut crer ce que lon appelle un bloc, cest--dire un ensemble dinstructions (suivies respectivement par des point-virgules) et comprises entre les accolades { et }. Les instructions if, while et for peuvent par exemple tre suivies dun bloc dinstructions excuter...

7.3 Linstruction if
Linstruction if est la structure de test la plus basique, on la retrouve dans tous les langages (avec une syntaxe diffrente...). Elle permet dexcuter une srie dinstruction si jamais une condition est ralise. La syntaxe de cette expression est la suivante :
if (condition ralise) { liste dinstructions; }

Remarques:

la condition doit tre entre des parenthses ;

il est possible de dnir plusieurs conditions remplir avec les oprateurs ET et OU (&& et ||) Par exemple linstruction suivante teste si les deux conditions sont vraies
if ((condition1)&&(condition2))

Linstruction suivante excutera les instructions si lune ou lautre des deux conditions est vraie :
if ((condition1)||(condition2))

sil ny a quune instruction, les accolades ne sont pas ncessaires...

les instructions situes dans le bloc qui suit else sont les instructions qui seront excutes si la ou les conditions ne sont pas remplies

16

7.3.1 Linstruction if ... else Linstruction if dans sa forme basique ne permet de tester quune condition, or la plupart du temps on aimerait pouvoir choisir les instructions excuter en cas de non ralisation de la condition... Lexpression if ... else permet dexcuter une autre srie dinstruction en cas de non-ralisation de la condition. La syntaxe de cette expression est la suivante:
if (condition ralise) { liste dinstructions } else { autre srie dinstructions }

7.4 Une faon plus courte de faire un test


Il est possible de faire un test avec une structure beaucoup moins lourde grce la structure suivante:
(condition) ? instruction si vrai : instruction si faux

Remarques:

la condition doit tre entre des parenthses

Lorsque la condition est vraie, linstruction de gauche est excute

Lorsque la condition est fausse, linstruction de droite est excute

En plus dtre excute, la structure ?: renvoie la valeur rsultant de linstruction excute. Ainsi, cette forme ?: est souvent utilise comme suit :
position = ((enAvant == 1) ? compteur+1 : compteur-1);

7.5 Linstruction switch


Linstruction switch permet de faire plusieurs tests de valeurs sur le contenu dune mme variable. Ce branchement conditionnel simplie beaucoup le test de plusieurs valeurs dune variable, car cette opration aurait t complique (mais possible) avec des if imbriqus. Sa syntaxe est la suivante:

17

switch (Variable) { case Valeur1: Liste dinstructions; break; case Valeur2: Liste dinstructions; break; case Valeurs...: Liste dinstructions; break; default: Liste dinstructions; break; }

Les parenthses qui suivent le mot cl switch indiquent une expression dont la valeur est teste successivement par chacun des case. Lorsque lexpression teste est gale une des valeurs suivant un case, la liste dinstruction qui suit celui-ci est excut. Le mot cl break indique la sortie de la structure conditionnelle. Le mot cl default prcde la liste dinstructions qui sera excute si lexpression nest jamais gale une des valeurs. Noubliez pas dinsrer des instructions break entre chaque test, ce genre doubli est difcile dtecter car aucune erreur nest signale... En effet, lorsque lon omet le break, lexcution continue dans les blocs suivants ! Cet tat de fait peut dailleurs tre utilis judicieusement an de faire excuter les mmes instructions pour diffrentes valeurs conscutives, on peut ainsi mettre plusieurs cases avant le bloc :
switch(variable) { case 1: case 2: { instructions excute pour variable = 1 ou pour variable = 2 } break; case 3: { instructions execute pour variable = 3 uniquement } break; default: { instructions execute pour toute autre valeur de variable } }

7.6 Les boucles


Les boucles sont des structures qui permettent dexcuter plusieurs fois la mme srie dinstructions jusqu ce quune condition ne soit plus ralise... On appelle parfois ces structures instructions rptitives ou bien itrations. La faon la plus commune de faire une boucle, est de crer un compteur (une variable qui sincrmente, cest--dire qui augmente de 1 chaque tour de boucle) et de faire arrter la boucle lorsque le compteur dpasse une certaine valeur.

18

7.6.1 La boucle for Linstruction for permet dexcuter plusieurs fois la mme srie dinstructions: cest une boucle! Dans sa syntaxe, il suft de prciser le nom de la variable qui sert de compteur (et ventuellement sa valeur de dpart, la condition sur la variable pour laquelle la boucle sarrte (basiquement une condition qui teste si la valeur du compteur dpasse une limite) et enn une instruction qui incrmente (ou dcrmente) le compteur. La syntaxe de cette expression est la suivante:
for (compteur; condition; modification du compteur) { liste dinstructions; }

Par exemple:
for (i=1; i<6; i++) { printf("%d", i); }

Cette boucle afche 5 fois la valeur de i, cest--dire 1,2,3,4,5 Elle commence i=1, vrie que i est bien infrieur 6, etc... jusqu atteindre la valeur i=6, pour laquelle la condition ne sera plus ralise, la boucle sinterrompra et le programme continuera son cours.

il faudra toujours vrier que la boucle a bien une condition de sortie (i.e le compteur sincrmente correctement)

une instruction printf(); dans votre boucle est un bon moyen pour vrier la valeur du compteur pas pas en lafchant!

il faut bien compter le nombre de fois que lon veut faire excuter la boucle: for(i=0;i<10;i++) for(i=0;i<=10;i++) for(i=1;i<10;i++) for(i=1;i<=10;i++) excute 10 fois la boucle (i de 0 9) excute 11 fois la boucle (i de 0 10) excute 9 fois la boucle (i de 1 9) excute 10 fois la boucle (i de 1 10)

7.6.2 Linstruction while Linstruction while reprsente un autre moyen dexcuter plusieurs fois la mme srie dinstructions. La syntaxe de cette expression est la suivante:
while (condition ralise) { liste dinstructions; }

Cette instruction excute la liste dinstructions tant que (while est un mot anglais qui signie tant que) la condition est ralise. La condition de sortie pouvant tre nimporte quelle structure conditionnelle, les risques de boucle innie (boucle dont la condition est toujours vraie) sont grands, cest--dire quelle risque de provoquer un plantage du programme en cours dexcution !

19

8 Les fonctions
8.1 La notion de fonction
On appelle fonction un sous-programme qui permet deffectuer un ensemble dinstruction par simple appel de la fonction dans le corps du programme principal. Les fonctions permettent dexcuter dans plusieurs parties du programme une srie dinstructions, cela permet une simplicit du code et donc une taille de programme minimale. Dautre part, une fonction peut faire appel elle-mme, on parle alors de fonction rcursive (il ne faut pas oublier de mettre une condition de sortie au risque sinon de ne pas pouvoir arrter le programme...).

8.2 La dclaration dune fonction


Avant dtre utilise, une fonction doit tre dnie car pour lappeler dans le corps du programme il faut que le compilateur la connaisse, cest--dire quil connaisse son nom, ses arguments et les instructions quelle contient. La dnition dune fonction sappelle "dclaration". La dclaration dune fonction se fait selon la syntaxe suivante:
type_de_donnee Nom_De_La_Fonction(type1 argument1, type2 argument2, ...) { liste dinstructions }

Remarques:

type_de_donnee reprsente le type de valeur que la fonction est sense retourner (char, int, oat,...) ;

Si la fonction ne renvoie aucune valeur, on la fait alors prcder du mot-cl void ;

Si aucun type de donne nest prcis (cela est trs vilain!), le type int est pris par dfaut ;

Le nom de la fonction suit les mmes rgles que les noms de variables: 1. le nom doit commencer par une lettre ; 2. un nom de fonction peut comporter des lettres, des chiffres et les caractres _ et & (les espaces ne sont pas autoriss!) ; 3. le nom de la fonction, comme celui des variables est sensible la casse (diffrenciation entre les minuscules et majuscules) ; 4. les arguments sont facultatifs, mais sil ny a pas darguments, les parenthses doivent rester prsentes ; 5. il ne faut pas oublier de refermer les accolades ;

Le nombre daccolades ouvertes (fonction, boucles et autres structures) doit tre gal au nombre daccolades fermes! ;

La mme chose sapplique pour les parenthses, les crochets ou les guillemets!

Une fois cette tape franchie, votre fonction ne sexcutera pas tant que lon ne fait pas appel elle quelque part dans la page!

8.3 Appel de fonction


Pour excuter une fonction, il suft de faire appel elle en crivant son nom (une fois de plus en respectant la casse) suivie dune parenthse ouverte (ventuellement des arguments) puis dune parenthse ferme:
Nom_De_La_Fonction();

20

Remarques:

le point virgule signie la n dune instruction et permet au navigateur de distinguer les diffrents blocs dinstructions ;

si jamais vous avez dni des arguments dans la dclaration de la fonction, il faudra veiller les inclure lors de lappel de la fonction (le mme nombre darguments spars par des virgules!).
Nom_De_La_Fonction(argument1, argument2);

8.4 Prototype dune fonction


Le prototype dune fonction est une description dune fonction qui est dnie plus loin dans le programme. On place donc le prototype en dbut de programme (avant la fonction principale main()). Cette description permet au compilateur de "vrier" la validit de la fonction chaque fois quil la rencontre dans le programme, en lui indiquant:

Le type de valeur renvoye par la fonction ;

Le nom de la fonction ;

Les types darguments.

Contrairement la dnition de la fonction, le prototype nest pas suivi du corps de la fonction (contenant les instructions excuter), et ne comprend pas le nom des paramtres (seulement leur type). Un prototype de fonction ressemble donc ceci3 :
Type_de_donnee_renvoyee Nom_De_La_Fonction(type_argument1, type_argument2, ...);

Voici quelques exemples de prototypes:


void Affiche_car(char, int); int Somme(int, int);

8.5 Les arguments dune fonction


Il est possible de passer des arguments une fonction, cest--dire lui fournir une valeur ou le nom dune variable an que la fonction puisse effectuer des oprations sur ces arguments ou bien grce ces arguments. Le passage darguments une fonction se fait au moyen dune liste darguments (spars par des virgules) entre parenthses suivant immdiatement le nom de la fonction. Le nombre et le type darguments dans la dclaration, le prototype et dans lappel doit correspondre au risque, sinon, de gnerer une erreur lors de la compilation... Un argument peut tre:

une constante ;

une variable ;

une expression ;

une autre fonction


prototype est une instruction, il est donc suivi dun point-virgule!

3 Le

21

8.6 Renvoi dune valeur par une fonction


La fonction peut renvoyer une valeur (et donc se terminer) grce au mot-cl return. Lorsque linstruction return est rencontre, la fonction value la valeur qui la suit, puis la renvoie au programme appelant (programme partir duquel la fonction a t appele). Une fonction peut contenir plusieurs instructions return, ce sera toutefois la premire instruction return rencontre qui provoquera la n de la fonction et le renvoi de la valeur qui la suit. La syntaxe de linstruction return est simple4 :
return valeur_ou_variable;

Le type de valeur retourn doit correspondre celui qui a t prcis dans la dnition (et le prototype).

4 Le

type de valeur retourn doit correspondre celui qui a t prcis dans la dnition (et le prototype)

22

9 Les structures en langage C


9.1 Type de donnes complexes
Les variables, telles que nous les avons vues, ne permettent de stocker quune seule donne la fois. Or, pour de nombreuses donnes, comme cela est souvent le cas, des variables distinctes seraient beaucoup trop lourdes grer. Heureusement, le langage C propose des structures de donnes permettant de stocker lensemble de ces donnes dans une "variable commune". Ainsi, pour accder ces valeurs il suft de parcourir la variable de type complexe compose de "variables" de type simple. Le langage C propose deux types de structures:

les tableaux: permettant de stocker plusieurs donnes de mme type ;

les structures: pouvent contenir des donnes htrognes.

9.2 La notion de tableau


On appelle tableau une variable compose de donnes de mme type, stocke de manire contigu en mmoire (les unes la suite des autres). Un tableau est donc une suite de cases (espace mmoire) de mme taille. La taille de chacune des cases est conditionne par le type de donne que le tableau contient. Les lments du tableau peuvent tre:

des donnes de type simple: int, char, oat, long, double, ... (la taille dune case du tableau est alors le nombre doctets sur lequel la donne est code) ;

des pointeurs (objets contenant une adresse mmoire. Ce type dentit sera expliqu dans les chapitres suivants) ;

des tableaux ;

des structures.

Voici donc une manire de reprsenter un tableau: donne

donne

donne

...

donne

donne

donne

Lorsque le tableau est compos de donnes de type simple, on parle de tableau monodimensionnel (ou vecteur) ;

Lorsque celui-ci contient lui mme dautres tableaux on parle alors de tableaux multidimensionnels (aussi matrice ou table)

9.3 Les tableaux unidimensionnels


9.3.1 Dclaration Un tableau unidimensionnel est un tableau qui contient des lments simples (des lments qui ne sont pas des tableaux). Un tableau unidimensionnel est donc une suite de "cases" de mme taille contenant des lments dun type donn (de la longueur de la case en quelque sorte). Un tableau contenant des entiers peut se reprsenter de la faon suivante: int int int ... int int int

En langage C, la syntaxe de la dnition dun tableau unidimensionnel est la suivante:


type Nom_du_tableau [Nombre dlments]

23

type dnit le type dlment que contient le tableau (rappel: un tableau en langage C est compos uniquement dlments de mme type), cest--dire quil dnit la taille dune case du tableau en mmoire

Nom_du_tableau est le nom que lon dcide de donner au tableau, le nom du tableau suit les mmes rgles quun nom de variable

Nombre dlments est un nombre entier qui dtermine le nombre de cases que le tableau doit comporter

Voici par exemple la dnition dun tableau qui doit contenir 8 lments de type char:
char Tableau [8]

9.3.2 Calcul de la taille du tableau Etant donn quun tableau est compos dun nombre x dlments dun type donn, la taille dun tableau est dtermine ds sa dnition. Pour connatre la taille dun tableau, cest--dire dterminer le nombre doctets que celui-ci occupe en mmoire, il y a deux possibilits:

Calculer manuellement la taille du tableau: il suft de multiplier la taille du type dlment par le nombre dlments qui composent le tableau ;

Utiliser loprateur sizeof(): loprateur sizeof() permet de retourner directement la taille de llments qui lui est pass en argument, ainsi en lui passant un tableau comme oprande, sizeof() est capable de vous retrourner directement la taille de celui-ci.

Voici diffrents exemples de tableaux, et leurs tailles respectives: Dnition du tableau char Tableau1[12] int Tableau2[10] float Tableau3[8] double Tableau4[15] 9.3.3 Accder aux lments Pour accder un lment du tableau, le nom que lon a donn celui-ci ne suft pas car il comporte plusieurs lments. Ainsi, on dnit un nombre appel indice (en anglais index) qui, combin avec le nom du tableau, permet de dcrire exactement chaque lment. Pour accder un lment du tableau, il suft donc de donner le nom du tableau, suivi de lindice de llment entre crochets:
Nom_du_tableau[indice]

Taille du tableau (en octets) 1 * 12 = 12 2 * 10 = 20 4 * 8 = 32 8 * 15 = 120

Lindice du premier lment du tableau est 0 ;

Un indice est toujours positif ;

Lindice du dernier lment du tableau est gal au nombre dlments - 1.

Ainsi, on accdera au 5me lment du tableau en crivant:


Nom_du_tableau[4]

24

9.3.4 Manipuler les lments Un lment du tableau (repr par le nom du tableau et son indice) peut-tre manipul exactement comme une variable, on peut donc effectuer des oprations avec (ou sur) des lments de tableau. Dnissons un tableau de 10 entiers :
int Toto[10];

Pour affecter la valeur 6 au huitime lment on crira :


Toto[7] = 6;

Pour affecter au 10me lment le rsultat de laddition des lments 1 et 2, on crira:


Toto[9] = Toto[0] + Toto[1];

9.3.5 Initialiser les lments Lorsque lon dnit un tableau, les valeurs des lments quil contient en sont pas dnies, il faut donc les initialiser, cest--dire leur affecter une valeur. Une mthode rustique consiste affecter des valeurs aux lments un par un 5 :
Toto[0] = Toto[1] = Toto[2] = 0;

Une manire plus lgante consiste utiliser le fait que pour passer dun lment du tableau llment suivant il suft dincrmenter son indice. Il est donc possible dutiliser une boucle qui va permettre dinitialiser successivement chacun des lments grce un compteur qui servira dindice:
int Toto[10]; int Indice; for (Indice = 0; Indice <= 9; Indice++) { Toto[Indice] = 0; }

Cette mthode, aussi utile soit elle, na dintrt que lorsque les lments du tableau doivent tre initialiss une valeur unique ou une valeur logique (proportionnelle lindice par exemple). Pour initialiser un tableau avec des valeurs spciques, il est possible dinitialiser le tableau la dnition en plaant entre accolades les valeurs, spares par des virgules:
int Toto[10] = {1, 2, 6, 5, 2, 1, 9, 8, 1, 5};

Le nombre de valeurs entre accolades ne doit pas tre suprieur au nombre dlments du tableau ;

les valeurs entre accolades doivent tre des constantes (lutilisation de variables provoquera une erreur du compilateur) ;

Si le nombre de valeurs entre accolades est infrieur au nombre dlments du tableau, les derniers ments sont initialiss 0 ;
de lutilisation dun tableau est alors bien maigre...

5 Lintrt

25

Il doit y avoir au moins une valeur entre accolades.

Ainsi, linstruction suivante permet dinitialiser tous les lments du tableau zro:
int Toto[10] = {0};

Il est conseill demployer le plus possible des constantes dans vos programmes, notamment pour la taille des tableaux. Le code ci-dessus peut scrire ainsi :
#define NB_ELEMENT_TOTO 10 int Toto[NB_ELEMENT_TOTO]; int Indice; for (Indice = 0; Indice < NB_ELEMENT_TOTO; Indice++) { Toto[Indice] = 0; }

Voici les avantages lis lutilisation de constantes :


Moins derreurs dexcution dues un dbordement difcile dceler ; Pour modier la taille du tableau il suft de changer le dene en dbut du code source ; Le code possde une lisibilit accrue.

9.4 Les tableaux multidimensionnels


Les tableaux multidimensionnels sont des tableaux qui contiennent des tableaux. Par exemple le tableau bidimensionnel (3 lignes, 4 colonnes) suivant, est en fait un tableau comportant 3 lments, chacun dentre eux tant un tableau de 4 lments:
   

est stock en mmoire de la manire suivante



9.4.1 Dnition Un tableau multidimensionnel se dnit de la manire suivante:


type Nom_du_tableau [a1][a2][a3] ... [aN]

Chaque lment entre crochets dsigne le nombre dlments dans chaque dimension ; Le nombre de dimension nest pas limit.

Un tableau dentiers positifs deux dimensions (3 lignes, 4 colonnes) se dnira avec la syntaxe suivante:
int Tableau [3][4]

On peut reprsenter un tel tableau de la manire suivante:

26

Tableau[0][0] Tableau[1][0] Tableau[2][0]

Tableau[0][1] Tableau[1][1] Tableau[2][1]

Tableau[0][2] Tableau[1][2] Tableau[2][2]

Tableau[0][3] Tableau[1][3] Tableau[2][3]

Il va de soi que cette reprsentation est arbitraire, car elle suppose que le premier indice est lindice de ligne, et le second est lindice de colonne. On aurait tout aussi bien pu reprsenter le tableau de la manire suivante: Tableau[0][0] Tableau[0][1] Tableau[0][2] Tableau[0][3] Tableau[1][0] Tableau[1][1] Tableau[1][2] Tableau[1][3] Tableau[2][0] Tableau[2][1] Tableau[2][2] Tableau[2][3]

On utilise toutefois gnralement la premire reprsentation, car elle correspond mieux la faon selon laquelle le tableau est stock en mmoire. 9.4.2 Initialiser les lments Linitialisation dun tableau multidimensionnel se fait peu prs de la mme faon que pour les tableaux unidimensionnels. Il y a donc plusieurs faons dinitialiser un tableau multidimensionnel:

Initialisation individuelle de chaque lment:


Nom_du_tableau [0][0] = 2; Nom_du_tableau [0][1] = 3; ..

Initialisation grce des boucles: Il faut faire des boucles imbriques correspondant chacune un indice dune dimension. Par exemple les lments de Tableau[3][4] pourront tre initialiss 0 par les instructions suivantes:
int i,j; for (i=0; i<=2; i++){ for (j=0; j<=3; j++){ Tableau[i][j] = 0; } }

Initialisation la dnition:
type Nom_du_tableau [Taille1][Taille2]...[TailleN] = {a1, a2, a3, ... a4};

Les valeurs sont attribus aux lments successifs en incrmentant dabord les indices de droite, cest--dire pour un tableau 2 dimensions: [0][0], [0][1], [0][2] ... puis [1][0] etc...

Initialisation grce la fonction memset:


int toto[10]; /* Met zro toute la zone mmoire */ memset(*toto, 0, sizeof(toto));

Synopsis de la fonction memset : 27

#include <string.h> void * memset ( void * buffer, int c, size_t num );

9.5 Diffrence entre une structure et un tableau


Un tableau permet de regrouper des lments de mme type, cest--dire cods sur le mme nombre de bit et de la mme faon. Toutefois, il est gnralement utile de pouvoir rassembler des lments de type diffrents tels que des entiers et des chanes de caractres. Les structures permettent de remdier cette lacune des tableaux, en regroupant des objets (des variables) au sein dune entit repre par un seul nom de variable. Les objets contenus dans la structure sont appels champs de la structure.

28

10 Les structures
10.1 Dclaration dune structure
Lors de la dclaration de la structure, on indique les champs de la structure, cest--dire le type et le nom des variables qui la composent:
struct Nom_Structure { type_champ1 Nom_Champ1; type_champ2 Nom_Champ2; type_champ3 Nom_Champ3; type_champ4 Nom_Champ4; type_champ5 Nom_Champ5; ... };

La dernire accolade doit tre suivie dun point-virgule!

Le nom des champs rpond aux critres des noms de variable ;

Deux champs ne peuvent avoir le mme nom ;

Les donnes peuvent tre de nimporte quel type hormis le type de la structure dans laquelle elles se trouvent.

Ainsi, la structure suivante est correcte:


struct MaStructure { int Age; char Sexe; char Nom[12]; float MoyenneScolaire; struct AutreStructure StructBis; /* en considerant que la structure AutreStructure est definie */ };

Par contre la structure suivante est incorrecte:


struct MaStructure { int Age; char Age; struct MaStructure StructBis; };

Il y a deux raisons cela:

Le nom de variable Age nest pas unique ;

Le type de donne struct MaStructure nest pas autoris ;

La dclaration dune structure ne fait que donner lallure de la structure, cest--dire en quelque sorte une dnition dun type de variable complexe. La dclaration ne rserve donc pas despace mmoire pour une variable structure (variable de type structure), il faut donc dnir une (ou plusieurs) variable(s) structure(s) aprs avoir dclare la structure... 29

10.2 Dnition dune variable structure


La dnition dune variable structure est une opration qui consiste crer une variable ayant comme type celui dune structure que lon a prcdemment dclar, cest--dire la nommer et lui rserver un emplacement en mmoire. La dnition dune variable structure se fait comme suit:
struct Nom_Structure Nom_Variable_Structuree;

Nom_Structure reprsente le nom dune structure que lon aura pralablement dclare. Nom_Variable_Structuree est le nom que lon donne la variable structuree. Il va de soi que, comme dans le cas des variables on peut dnir plusieurs variables structures en les sparant avec des virgules:
struct Nom_Structure Nom1, Nom2, Nom3, ...;

Soit la structure Personne:


struct Personne{ int Age; char Sexe; };

On peut dnir plusieurs variables structures:


struct Personne Pierre, Paul, Jacques;

10.3 Accs aux champs dune variable structure


Chaque variable de type structure possde des champs reprs avec des noms uniques. Toutefois le nom des champs ne suft pas pour y accder tant donn quils nont de contexte quau sein de la variable structure... Pour accder aux champs dune structure on utilise loprateur de champ (un simple point) plac entre le nom de la variable structure que lon a dnit et le nom du champ:
Nom_Variable.Nom_Champ;

Ainsi, pour affecter des valeurs la variable Pierre (variable de type struct Personne dnie prcdemment), on pourra crire:
Pierre.Age = 18; Pierre.Sexe = M;

10.4 Tableaux de structures


Etant donn quune structure est compose dlments de taille xes, il est possible de crer un tableau ne contenant que des lments du type dune structure donne. Il suft de crer un tableau dont le type est celui de la structure et de le reprer par un nom de variable:

30

struct Nom_Structure Nom_Tableau[Nb_Elements];

Chaque lment du tableau reprsente alors une structure du type que lon a dni... Le tableau suivant (nomm Repertoire) pourra par exemple contenir 8 variables structures de type struct Personne:
struct Personne Repertoire[8];

De la mme faon, il est possible de manipuler des structures dans les fonctions.

31

11 La notion de pointeur
11.1 Dnition dun pointeur
Un pointeur est une variable contenant ladresse dune autre variable dun type donn. La notion de pointeur fait souvent peur car il sagit dune technique de programmation trs puissante, permettant de dnir des structures dynamiques, cest--dire qui volue au cours du temps (par opposition aux tableaux par exemple qui sont des structures de donnes statiques, dont la taille est ge la dnition

11.2 Les pointeurs 11.3 Comprendre la notion dadresse


Comme nous lavons vu, un pointeur est une variable qui permet de stocker une adresse, il est donc ncessaire de comprendre ce quest une adresse. Lorsque lon excute un programme, celui-ci est stock en mmoire, cela signie que dune part le code excuter est stock, mais aussi que chaque variable que lon a dni a une zone de mmoire qui lui est rserve, et la taille de cette zone correspond au type de variable que lon a dclar. En ralit la mmoire est constitue de plein de petites cases de 8 bits (un octet). Une variable, selon son type (donc sa taille), va ainsi occuper une ou plusieurs de ces cases (une variable de type char occupera une seule case, tandis quune variable de type long occupera 4 cases conscutives). Chacune de ces "cases" (appeles blocs) est identie par un numro. Ce numro sappelle adresse. On peut donc accder une variable de 2 faons:

grce son nom ;

grce ladresse du premier bloc allou la variable.

Il suft donc de stocker ladresse de la variable dans un pointeur (il est prvu pour cela) an de pouvoir accder celle-ci (on dit que lon "pointe vers la variable").

Le schma ci-dessus montre par exemple par quel mcanisme il est possible de faire pointer une variable (de type pointeur) vers une autre. Ici le pointeur stock ladresse 24 pointe vers une variable stocke ladresse 253 (les valeurs sont bien videmment arbitraires).

11.4 Comment connat-on ladresse dune variable ?


En ralit vous naurez jamais crire ladresse dune variable, dautant plus quelle change chaque lancement de programme tant donn que le systme dexploitation alloue les blocs de mmoire qui sont libres, et ceux-ci ne sont pas les mmes chaque excution. Ainsi, il existe une syntaxe permettant de connatre ladresse dune variable, connaissant son nom: il suft de faire prcder le nom de la variable par le caractre & ("ET commercial") pour dsigner ladresse de cette variable:
&Nom_de_la_variable

32

11.5 Intrt des pointeurs


Les pointeurs ont un grand nombre dintrts:

Ils permettent de manipuler de faon simple des donnes pouvant tre importantes (au lieu de passer une fonction un lment trs grand (en taille) on pourra par exemple lui fournir un pointeur vers cet lment...

Les tableaux ne permettent de stocker quun nombre x dlments de mme type. En stockant des pointeurs dans les cases dun tableau, il sera possible de stocker des lments de taille diverses, et mme de rajouter des lments au tableau en cours dutilisation (cest la notion de tableau dynamique qui est trs troitement lie celle de pointeur)

Il est possible de crer des structures chanes, cest--dire comportant des maillons

11.6 Dclaration dun pointeur


Un pointeur est une variable qui doit tre dnie en prcisant le type de variable pointe, de la faon suivante:
type * Nom_du_pointeur

Le type de variable pointe peut-tre aussi bien un type primaire (tel que int, char, ...) quun type complexe (tel que struct, ...). Un pointeur doit prfrentiellement tre typ ! Il est toutefois possible de dnir un pointeur sur void, cest dire sur quelque chose qui na pas de type prdni (void * toto). Ce genre de pointeur sert gnralement de pointeur de transition, dans une fonction gnrique, avant un transtypage permettant daccder effectivement aux donnes pointes. Grce au symbole * le compilateur sait quil sagit dune variable de type pointeur et non dune variable ordinaire, de plus, tant donn que vous prcisez (obligatoirement) le type de variable, le compilateur saura combien de blocs suivent le bloc situ ladresse pointe.

11.7 Initialisation dun pointeur


Aprs avoir dclar un pointeur il faut linitialiser. Cette dmarche est trs important car lorsque vous dclarez un pointeur, celui-ci contient ce que la case o il est stock contenait avant, cest--dire nimporte quel nombre. Autrement dit, si vous ninitialisez pas votre pointeur, celui-ci risque de pointer vers une zone hasardeuse de votre mmoire, ce qui peut tre un morceau de votre programme ou ... de votre systme dexploitation! Un pointeur non initialis reprsente un danger! Pour initialiser un pointeur, il faut utiliser loprateur daffectation = suivi de loprateur dadresse & auquel est accoll un nom de variable (celle-ci doit bien sr avoir t dnie avant...):
Nom_du_pointeur = &nom_de_la_variable_pointee;

Par exemple:
int a = 2; char b; int *p1; char *p2; p1 = &a; p2 = &b;

33

11.8 Accder une variable pointe


Aprs (et seulement aprs) avoir dclar et initialis un pointeur, il est possible daccder au contenu de ladresse mmoire pointe par le pointeur grce loprateur *. La syntaxe est la suivante: Par exemple:
int a = 2; *p1 = 10; *p2 = a;

Aprs ces deux instructions, le contenu des variables a et b sera respectivement 10 et 97 (61 en hexadcimal, le code ASCII associ au caractre a). Si vous dsirez utiliser cette notation dans une expression plus complexe, il sera ncessaire demployer des parenthses: Par exemple:
a = (*p)++;

34

12 Les chaines de caractres


12.1 Quest-ce quune chaine de caractres?
Une chane de caractre (appele string en anglais) est une suite de caractres, cest--dire un ensemble de symboles faisant partie du jeu de caractres, dni par le code ASCII. En langage C, une chane de caractres est un tableau, comportant plusieurs donnes de type char, dont le dernier lment est le caractre nul \0, cest--dire le premier caractre du code ASCII (dont la valeur est 0). Ce caractre est un caractre de contrle (donc non afchable) qui permet dindiquer une n de chane de caractres. Ainsi une chaine compose de n lments sera en fait un tableau de n+1 lments de type char. On peut par exemple reprsenter la chane "Bonjour" de la manire suivante:

12.2 Crer une chaine de caractres


Pour dnir une chane de caractres en langage C, il suft de dnir un tableau de caractre. Le nombre maximum de caractres que comportera la chane sera gal au nombre dlments du tableau moins un (rserv au caractre de n de chane.
char Nom_du_tableau[Nombre_d_elements]

Le nombre dlments que comporte le tableau dnit la taille maximale de la chaine, on peut toutefois utiliser partiellement cet espace en insrant le caractre de n de chane lemplacement dsir dans le tableau. Astuce! en dnissant le tableau de la manire suivante, vous mettez en vidence le nombre de caractre maximal de la chane:
char Nom_du_tableau[Nombre_d_elements + 1]

Par exemple:
char Chaine[50 + 1]

12.3 Initialiser une chaine de caractres


Comme gnralement en langage C, il faut initialiser votre chane de caractre, cest--dire remplir les cases du tableau avec des caractres, sachant que celui-ci devra obligatoirement contenir le caractre de n de chane \0. Il y a deux faons de procder:

remplir manuellement le tableau case par case ;

utiliser les fonctions de manipulation de chane fournies dans les librairies standards.

Voici un exemple dinitialisation manuelle de chane de caractres:

35

#include <stdio.h> void main(){ char Chaine[20+1]; Chaine[0]= B; Chaine[1]= o; Chaine[2]= n; Chaine[3]= j; Chaine[4]= o; Chaine[5]= u; Chaine[6]= r; Chaine[7]= \0; }

Voici une autre faon (plus simple) dinitialiser une chane de caractres:
#include <stdio.h> void main(){ char Chaine[20+1]={ B, o, n, j, o, u, r, \0 }; }

12.4 Les fonctions de manipulation de chanes de caractres


De nombreuses fonctions de manipulation de chane sont directement fournies. Ces fonctions se trouvent dans le chier den-tte <string.h>, cest la raison pour laquelle il faut ajouter la ligne suivante en dbut de programme:
#include <string.h>

Le chier <string.h> contient les prototypes de nombreuses fonctions permettant de simplier lutilisation et la manipulation de chanes (environ une quarantaine). Certaines de ces fonctions seront tudies dans les chapitres suivants...

36

13 Les Listes chaines


13.1 La notion de structure autorferrentielle
Une structure autorferrentielle (parfois appele structure rcursive) correspond une structure dont au moins une des champs contient un pointeur vers une structure de mme type. De cette faon on cre des lments (appels parfois noeuds ou liens) contenant des donnes, mais, contrairement un tableau, celles-ci peuvent tre parpilles en mmoire et relies entre-elles par des liens logiques (des pointeurs), cest--dire un ou plusieurs champs dans chaque structure contenant ladresse dune ou plusieurs structures de mme type.

Lorsque la structure contient des donnes et un pointeur vers la structure suivante on parle de liste chane

Lorsque la structure contient des donnes, un pointeur vers la structure suivante, et un pointeur vers la structure prcdente on parle de liste chane double

Lorsque la structure contient des donnes, un pointeur vers une premire structure suivante, et un pointeur vers un seconde, on parle darbre binaire

13.2 Quest-ce quune liste chaine?


Une liste chane est une structure comportant des champs contenant des donnes et un pointeur vers une structure de mme type. Ainsi, la structure correspondant une liste chane contenant une chane de 15 caractres et un entier ressemble ceci:
struct Nom_de_la_liste { char Chaine[16]; int Entier; struct Nom_de_la_liste * pSuivant; };

On reprsente gnralement cette structure de la manire suivante: Chaine Entier Pointeur vers suivant Une liste chanes se reprsente donc de la faon suivante:

En ralit la dclaration de la structure et la rcursivit de celle-ci grce des pointeurs est ncessaire car cela cre une chane denregistrements lis par des liens logiques, mais cela nest pas sufsant. En effet, il est ncessaire de conserver une "trace" du premier enregistrement an de pouvoir accder aux autres, cest pourquoi un pointeur vers le premier lment de la liste est indispensable. Ce pointeur est appel pointeur de tte. Dautre part, tant donn que le dernier enregistrement ne pointe vers rien, il est ncessaire de donner son pointeur la valeur NULL:

37

Pour crer une liste chane en langage C, il sagit dans un premier temps de dnir la structure de donnes, ainsi quun pointeur vers une structure du type de celle dnie prcdemment, an de pointer vers la tte de la liste, cest--dire le premier enregistrement:
struct Liste { char Chaine[16]; struct Liste * pSuivant; }; struct Liste *Nouveau; struct Liste *Tete; Tete = NULL;

13.3 Ajout dun premier lment


Une fois la structure et les pointeurs dnis, il est possible dajouter un premier maillon la liste chane, puis de laffecter au pointeur Tete. Pour cela il est ncessaire :

dallouer la mmoire ncessaire au nouveau maillon grce la fonction malloc, selon la syntaxe suivante:
Nouveau = (Liste*)malloc(sizeof(struct Liste));

dassigner au champ "pointeur" du nouveau maillon, la valeur du pointeur vers le maillon de tte :
Nouveau->pSuivant = Tete;

dnir le nouveau maillon comme maillon de tte :


Tete = Nouveau;

Il est conseill de tester la valeur renvoye en retour par la fonction malloc() an de savoir si lallocation dynamique de mmoire sest droule correctement

13.4 Ajout dun lment en n de liste


Lajout dun lment la n de la liste chane est similaire, la diffrence prs quil faut dnir un pointeur (appel gnralement pointeur courant) an de parcourir la liste jusqu atteindre le dernier maillon (celui dont le pointeur possde la valeur NULL. Les tapes suivre sont donc:

la dnition dun pointeur courant:


struct Liste * pCourant;

38

le parcours de la liste chane jusquau dernier noeud:


if (Tete != NULL) { pCourant = Tete; while (pCourant->pSuivant != NULL) pCourant = pCourant->pSuivant; }

lallocation de mmoire pour le nouvel lment:


Nouveau = (Liste*)malloc(sizeof(struct Liste));

faire pointer le pointeur courant vers le nouveau noeud, et le nouveau noeud vers NULL:
Courant->pSuivant = Nouveau; Nouveau->pSuivant = NULL;

13.5 Quest-ce quune liste chaine double?


Une liste chane double est base sur le mme principe que la liste chane simple, la diffrence prs quelle contient non seulement un pointeur vers le maillon suivant mais aussi un pointeur vers le maillon prcdent, permettant de cette faon le parcours de la liste dans les deux sens. Ainsi, la structure correspondant une liste chane double contenant une chane de 15 caractres et un entier ressemble ceci:
struct Liste { char Chaine[16]; int Entier; struct Liste * pSuivant; struct Liste * pPrecedent };

On reprsente gnralement cette structure de la manire suivante: donnes Pointeur vers suivant Pointeur vers prcdent Une liste chane double se reprsente donc de la faon suivante:

39