Vous êtes sur la page 1sur 56

UNIVERSITE DE LABE

FACULTE DES SCIENCES ET TECHNIQUES


DEPARTEMENT INFORMATIQUE

Support de Cours de
Langage C
Licence Informatique
M. Koliko DELAMOU

Niveau L2 S3

Année 2018
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

PROGRAMME DE LANGAGE C

Chapitre 1 : les Bases……………………………………………3

Chapitre 2 : les Tableaux………………………………………..27

Chapitre 3 : les fonctions………………………………………..30

Chapitre 4 : les Pointeurs ……………………………………….40

Chapitre 5 : les chaines de caractères……………………………48

Chapitre 6 : les Structures et les Enumérations………………….54

Chapitre 7 : les Fichiers………………………………………….60

Chapitre 8 : Les Directives du préprocesseur …………………..

1
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Avant-Propos

Le langage C a été créé en 1972 par Denis Ritchie avec un objectif relativement limité : écrire
un système d'exploitation (UNIX).
Mais ses qualités "opérationnelles" l'ont très vite fait adopter par une large communauté de
programmeurs.
Une première "définition" du langage est apparue en 1978 avec l'ouvrage de Kernighan et
Ritchie The C programming language.
Mais le langage a continué d'évoluer après cette date à travers les différents compilateurs qui
ont vu le jour. Son succès international a contribué à sa normalisation, d'abord par l'ANSI
(American National Standard Institute), puis par l'ISO (International Standardization
Organisation), plus récemment en 1993 par le CEN (Comité Européen de Normalisation) et
enfin, en 1994, par l'AFNOR (Association Française pour la NORmalisation). En fait, et fort
heureusement, toutes ces normes sont identiques, et l'usage veut qu'on parle de "C ANSI" ou
de "C norme ANSI".
Cet ouvrage a été conçu comme un cours de programmation en langage C. Suivant notre
démarche habituelle, héritée de notre expérience de l'enseignement, nous présentons toujours
les notions fondamentales sur un ou plusieurs exemples avant d'en donner plus formellement
la portée générale. Souvent constitués de programmes complets, ces exemples permettent
l'auto expérimentation.
Pourquoi utiliser le langage C ?

Il existe de nombreux langages de programmation de haut niveau comme le C, le Pascal, ou le


Basic. Ils sont tous excellents et conviennent pour la plupart des tâches de programmation.
Toutefois, les professionnels placent le langage C en tête de liste pour plusieurs raisons :
 Il est souple et puissant. Ce que vous pourrez accomplir avec ce langage n‟est limité
que par votre imagination. Vous n‟aurez aucune contrainte. Le langage C est utilisé
pour des projets aussi variés que des systèmes d‟exploitation, des traitements de
textes, des graphiques, des tableurs ou même des compilateurs pour d‟autres langages.
 Lorsqu‟une nouvelle architecture (nouveau processeur, nouveau système
d‟exploitation...) apparaît, le premier langage disponible est généralement le C car
contrairement à d‟autres, il est facile à porter. De plus, un compilateur C est souvent
disponible sur les ordinateurs (à l‟exception de Windows malheureusement), ce qui
n‟est pas le cas pour les autres langages.
 Avec la norme ANSI, le C est devenu un langage portable. Cela signifie qu‟un
programme C écrit pour un type d‟ordinateur (un PC IBM, par exemple) peut être
compilé pour tourner sur un autre système (comme un DEC VAX) avec très peu ou
aucune modification.
 Le langage C contient peu de mots. Une poignée d‟expressions appelées mots clés
servent de bases pour l‟élaboration des fonctions. On pourrait penser, à tort, qu‟un
langage possédant plus de mots clés (quelquefois appelés mots réservés) pourrait être
plus puissant. Lorsque vous programmerez avec ce langage, vous vous apercevrez que
vous pouvez réaliser n‟importe quelle tâche.
 Le langage C est modulaire. Son code peut (et devrait) être écrit sous forme de sous-
programmes appelés fonctions. Ces fonctions peuvent être réutilisées pour d‟autres
applications ou programmes. Si vous passez des informations à ces fonctions, vous
obtenez du code réutilisable.
Comme vous pouvez le constater, le choix du C en tant que premier langage de
programmation est excellent. Vous avez certainement entendu parler de C++. Ce langage
s‟appuie sur une technique de programmation appelée programmation orientée objet.

2
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

C++ était initialement une version améliorée du C, à savoir un C disposant de fonctions


supplémentaires pour la programmation orientée objet. Le C++ est aujourd‟hui un langage à
part entière. Si vous êtes amenés à étudier ce langage, ce que vous aurez appris du C vous
aidera grandement.
Un autre langage, également basé sur C, a été l‟objet d‟une attention toute particulière. Il
s‟agit de Java. Si vous décidez de vous orienter vers la programmation Java, vous découvrirez
rapidement qu‟il existe de nombreuses similitudes entre ces deux langages.

CHAPITRE I : LES BASES

Ce chapitre vous propose une première approche en langage C. Vous y découvrirez la manière
dont s‟utilisent les instructions de base (déclaration, affectation, lecture et écriture) ainsi que
deux des structures fondamentales (boucle et choix).

I.1) Quelques mots du vocabulaire dans le domaine de la programmation


a) Programmer : c‟est réaliser des programmes informatiques. Les programmes
informatiques demandent à l‟ordinateur d‟effectuer des actions.
b) Langage de programmation : c‟est un ensemble de règles syntaxique
compréhensible par l‟ordinateur et permettant d‟écrire des programmes.
N.B : il existe des langages de programmation de haut niveau et de bas niveau.
Plus un langage est de haut niveau, plus il est proche de notre langue.
c) Le code source : est le code d‟un programme écrit dans un langage de
programmation.
d) Instruction : est une ligne de code terminée par un point-virgule
e) Le langage binaire ou Langage Machine : est le langage informatique de
l‟ordinateur.
f) Compilateur : est un programme qui traduit le code source d‟un programme en
langage machine.
g) Exécutable : est le fichier final obtenu après compilation.
I.2) Les outils pour programmer.
Pour programmer, il faut :
a) Un éditeur de texte : pour écrire le code source du programme (le bloc note,
nodpad, nodpad++…)
b) Un compilateur : pour compiler le code source.
c) Un debugger: pour détecter les erreurs pendant la compilation.
L‟utilisation séparée de ses trois outils est très complexe, c‟est pourquoi de nos
jours il existe les IDE (Integrated Development Environnement ou Environnement
de Développement Intégré en français) qui sont des logiciels ayant les trois outils à
leur sein.
Exemple codeblocks, borlanC, borlanC++, devC++, turbo Pascal, visual C++,
éclipse, etc…
I.3) Quelques règles d’écriture
Ce paragraphe vous expose un certain nombre de règles générales intervenant dans
l'écriture d'un programme en langage C.
a) Les identificateurs :

3
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Les identificateurs servent à désigner les différents "objets" manipulés par le


programme : variables, fonctions, etc. Comme dans la plupart des langages, ils sont
formés d'une suite de caractères choisis parmi les lettres ou les chiffres, le premier
d'entre eux étant nécessairement une lettre.
En ce qui concerne les lettres :
- le caractère "souligné" (_) est considéré comme une lettre. Il peut donc apparaître en
début d'un identificateur. Voici quelques identificateurs corrects :
lg_lig valeur_5 _total _89
- les majuscules et les minuscules sont autorisées mais ne sont pas équivalentes
(contrairement, par exemple, à ce qui se produit en Pascal). Ainsi, en C, les
identificateurs ligne et Ligne désignent deux objets différents.
En ce qui concerne la longueur des identificateurs, la norme ANSI prévoit qu'au moins
les 31 premiers caractères soient "significatifs" (autrement dit, deux identificateurs qui
diffèrent par leurs 31 premières lettres désigneront deux objets différents).
b) Les mots clés :
Certains "mots clés" sont réservés par le langage à un usage bien défini et ne peuvent
pas être utilisés comme identificateurs.
En voici la liste, classée par ordre alphabétique
______________________________________________
auto default float register struct volatile
break do for return switch while
case double goto short typedef
char else if signed union
const enum int sizeof unsigned
continue extern long static void
que l'on peut ranger en catégories :
• les spécificateurs de stockage
auto register static extern typedef
• les spécificateurs de type
char double enum float int long short signed struct union unsigned void
• les qualificateurs de type
Const volatile
• les instructions de contrôle
break case continue default do else for goto if switch while
• divers
return sizeof
c) Les commentaires
Il s'agit de textes explicatifs destinés aux lecteurs du programme et qui n'ont aucune
incidence sur sa compilation.
Ils sont formés de caractères quelconques placés entre les symboles /* et */. Ils
peuvent apparaître à tout endroit du programme où un espace est autorisé.
Voici quelques exemples de commentaires :
/*Ceci est un commentaire*/
/* commentaire s'étendant
sur plusieurs lignes
de programme source */
On peut aussi utiliser // pour un commentaire s‟étendant sur une seule ligne.
// Ceci est un commentaire.
I.4) CREATION D’UN PROGRAMME EN C

4
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Nous vous fournissons ici quelques indications générales (s'appliquant à n'importe quel
environnement) concernant ce que l'on pourrait appeler les grandes étapes de la création d'un
programme.
Étape 1 Utilisez un éditeur pour créer le code source. Par convention, ce fichier doit avoir
l‟extension .c (par exemple, monprog.c, database.c, etc.).
Étape 2 Compilez votre programme. Si le compilateur ne rencontre pas d‟erreur dans votre
code source, vous obtenez un fichier objet du même nom que votre fichier source avec une
extension .obj ou .o (par exemple, monprog.c est compilé en monprog.o). Si le code source
contient des erreurs, le compilateur échoue et vous les affiche pour correction.
Étape 3 Exécutez la liaison. Si aucune erreur n‟apparaît, vous obtenez un programme
exécutable dans un fichier du même nom que le fichier objet (avec une extension .exe sur
Windows par exemple, monprog.obj devient monprog.exe).
Étape 4 Exécutez votre programme. Contrôlez les résultats obtenus et recommencez à l‟étape
1 si des modifications sont nécessaires dans le fichier source.

I.5 LES TYPES DE BASE EN C


I.5.1 La notion de type : en Langage C le type d‟un objet est un mot qui accompagne
l‟objet et qui désigne sa nature et permet son stockage dans la mémoire RAM.
Les types de base du langage C se répartissent en trois grandes catégories en fonction de la
nature des informations qu‟ils permettent de représenter :
- Les nombres entiers ;
- Les nombres réels ou flottants
- Les caractères
I.5.1.1 le Type entier
Il est désigné par le mot clé int. C permet qu‟on puisse stocker sur une machine jusqu‟à trois
tailles différentes d‟entier dont les détails sont donnés par le tableau ci-dessous
Nom Taille (t) Nombre de valeur (28*t) Code format
Short 1 octet 28 %hd
16
Int 2 octets 2 %d
Long 4 octets 232 %ld
Entiers non signés
Par défaut, les entiers permettent de stocker des valeurs de signe quelconque. Si on préfixe un
type entier par unsigned, on le restreint à des valeurs uniquement positives. Dans ce cas, on a
Nom Taille (t) Nombre de valeur (28*t) Valeur min Valeur max Code format
Unsigned 1 octet 28 0 28-1 %hu
Short
Unsigned 2 octets 216 0 216-1 %u
Int
Unsigned 4 octets 232 0 232-1 %lu
Long

I.5.1.2 le Type réel ou flottant


Les flottants servent à représenter les réels. Leur nom vient du fait qu'on les représente de
façon scientifique : un nombre décimal (à virgule) muni d'un exposant (un décalage de la
virgule). Trois types de base servent à représenter les flottants :
Nom Taille Code format
Float 4 octets %f
Double 8 octets %lf
Long double 10 octets %lg

5
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Il est conventionnel d'écrire des littéraux flottants avec un point, par exemple l'approximation
à 10 -2 près de π s'écrit 3.14. Il est aussi possible d'utiliser la notation scientifique, par
exemple le décimal 1 000 s'écrit 1e 3, à savoir 1.10 3 .
I.5.1.3 le Type caractère
Ce type est désigné en C par le mot clé char. Il occupe 1 octet en mémoire. Les types
caractères regroupent l‟ensemble des lettres majuscules et minuscules, des chiffres, des signes
de ponctuation et des différents séparateurs, etc…
Les caractères non imprimables : ce sont des caractères qui ne sont pas affichés à l‟écran
d‟exécution du programme mais réalisent des actions bien définies.
Voici la liste des principaux caractères non imprimables.
Caractères Signification
\a Cloche ou bip sonore
\b Retour arrière (backspace)
\f Saut de page
\r Retour chariot
\n Saut de ligne
\t Tabulation Horizontale
\v Tabulation verticale
\\ Le caractère (\)
\? Le caractère ( ?)
\‟ Le caractère ( ‟)
\” Le caractère ( ‟‟)
I.5.1.4 Les booléens en C : en C le type booléen est tout simplement une variable de type
entier qui ne peut avoir que deux valeurs : « 0 qui correspond à faux » ou « 1 qui correspond à
vrai »
I.6) LES OPERATEURS
Le langage C est l‟un des langages le plus riche en opérateurs. Cette richesse se manifeste tout
d‟abord au niveau des opérateurs d‟affectation et d‟incrémentation.
I.6.1) Les opérateurs arithmétiques : les opérateurs arithmétiques qu‟on rencontre en C
sont :
Opérateurs Symbole Exemple
Addition + Expr1+expr2
Soustraction - Expr1-exp2
Multiplication * Expr1*expr2
Division / Expr1/expr2
Modulo (reste de la division) % Expr1%expr2
I.6.2) Les opérateurs relationnels ou de comparaison

Opérateurs Symbole Exemple


Supérieur > Expr1>expr2
Supérieur ou égale >= Expr1>=exp2
inférieur < Expr1<expr2
Inférieur ou égale <= Expr1<=expr2
Egale == Expr1==expr2
Différent de != Expr1 !=expr2
I.6.3) Les opérateurs logiques

Opérateurs Symbole exemple

6
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

ET && Expr1&&expr2
Ou || Expr1||exp2
Non ! !Expr1
I.6.4) L’opérateur d’affectation :

Nous avons déjà eu l'occasion de remarquer que :


i = 5 était une expression qui :
- réalisait une action : l'affectation de la valeur 5 à i,
- possédait une valeur : celle de i après affectation, c'est-à-dire 5.
Cet opérateur d'affectation (=) peut faire intervenir d'autres expressions comme dans :
c=b+3
La faible priorité de cet opérateur = (elle est inférieure à celle de tous les opérateurs
arithmétiques et de comparaison) fait qu'il y a d'abord évaluation de l'expression b + 3. La
valeur ainsi obtenue est ensuite affectée à c.
En revanche, il n'est pas possible de faire apparaître une expression comme premier opérande
de cet opérateur =. Ainsi, l'expression suivante n'aurait pas de sens : c + 5 = x
I.6.5 Notion de lvalue
Nous voyons donc que l‟opérateur d'affectation impose des restrictions sur son premier
opérande. En effet, ce dernier doit être une référence à un emplacement mémoire dont on
pourra effectivement modifier la valeur.
Dans les autres langages, on désigne souvent une telle référence par le nom de variable.
En langage C, il faut introduire un mot nouveau : la lvalue. Ce terme désigne une valeur à
gauche, c'est-à-dire tout ce qui peut apparaître à gauche d'un opérateur d'affectation.
I.6.5) Les opérateurs d’affectation composée :

En C, chaque opérateur arithmétique peut être associé à l‟opérateur d‟affectation ordinaire


pour donner des opérateurs d‟affectation composée. Ces opérateurs sont utilisés dans des
expressions où un objet se trouve au premier et au second membre d‟une affectation.
Exemple : A=A+B (l‟objet A est dans les deux membres de cette affectation).
Les détails de ces opérateurs sont donnés dans le tableau ci-dessous.

Opérateurs Symbole Exemple


Affectation composé sur + += A=A+B équivaut à A+=B
Affectation composé sur - -= A=A-B équivaut à A-=B
Affectation composé sur * *= A=A*B équivaut à A*=B
Affectation composé sur / /= A=A/B équivaut à A/=B
Affectation composé sur % %= A=A%B équivaut à A%=B
I.6.6) Les opérateurs d’incrémentation et décrémentation :
Dans des programmes écrits dans un langage autre que C, on rencontre souvent des
expressions telles que : A=A+1 ; B=B-1 qui incrémentent (ajouter 1à la valeur initiale de A)
ou qui décrémentent (diminuer de 1 la valeur initiale de B).
Opérateurs Symbole
Incrémentation ++A (pré incrémentation)
A++ (post incrémentation)
Décrémentation --A (pré décrémentation)
A-- (post décrémentation)
En C, ces actions peuvent être réalisées par des opérateurs unaires : (++A, A++) et (--A, A--
)

7
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

NB : pris simplement, les opérateurs de pré incrémentation et de post incrémentation sont


équivalents.
Exemple A=5, ++A nous donne 6 et A++ nous donne aussi 6.
Mais dans des expressions, ++A a pour effet d‟incrémenter de 1 la valeur de A, et sa valeur
est celle de A après incrémentation.
Exemple : dans l‟expression X=++A-5 : la valeur de A sera 6 et celle de X est 1. En revanche
quand on écrit X=A++-5 : la valeur de A sera 6 et celle de X sera 0.
Il en est de même pour la décrémentation.
I.6.7) L’opérateur virgule
Une expression peut être constituée d'une suite d'expressions séparées par des virgules :
expression1, expression2, ..., expressionn
Cette expression est alors évaluée de gauche à droite. Sa valeur sera la valeur de l'expression
de droite. Par exemple, le programme
Main ( )
{
int a, b;
b = ((a = 3), (a + 2));
printf("\n b = %d \n",b);
}
imprime b = 5.
I.6.7) L’opérateur conditionnel ternaire
L'opérateur conditionnel ? est un opérateur ternaire. Sa syntaxe est la suivante :
condition ? expression1 : expression2
Cette expression est égale à expression1 si condition est satisfaite, et à expression2 sinon. Par
exemple, l'expression
x >= 0 ? x : -x correspond à la valeur absolue d'un nombre. De même l'instruction
m = ((a > b) ? a : b); affecte à m le maximum de a et de b.
I.6.8) L’opérateur de conversion de type
L'opérateur de conversion de type, appelé cast, permet de modifier explicitement le type d'un
objet. On écrit (type) objet
Par exemple,
main()
{
int i = 3, j = 2;
printf("%f \n",(float)i/j);
} retourne la valeur 1.5.
I.6.9) L'opérateur adresse
L'opérateur d'adresse & appliqué à une variable retourne l'adresse mémoire de cette variable.
La syntaxe est &objet
I.6.10) L'opérateur sizeof
L'opérateur sizeof, dont l'emploi ressemble à celui d'une fonction, fournit la taille (en octets.
Par exemple, dans une implémentation où le type int est représenté sur 2 octets et le type
double sur 8 octets, si l'on suppose que l'on a affaire à ces déclarations :
int n ;
double z ;
l'expression sizeof(n) vaudra 2,
l'expression sizeof(z) vaudra 8.
Cet opérateur peut également s'appliquer à un type de nom donné. Ainsi, dans
l'implémentation précédemment citée :
8
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

sizeof(int) vaudra 2,
sizeof(double) vaudra 8.
Quelle que soit l'implémentation, sizeof(char) vaudra toujours 1 (par définition, en quelque
sorte).
Cet opérateur offre un intérêt :
- lorsque l'on souhaite écrire des programmes portables dans lesquels il est nécessaire de
connaître la taille exacte de certains objets,
- pour éviter d'avoir à calculer soi-même la taille d'objets d'un type relativement complexe
pour lequel on n'est pas certain de la manière dont il sera implémenté par le compilateur. Ce
sera notamment le cas des structures.

I.8) NOTION DE VARIABLE


I.8.1 Définition : une variable est tout objet dont le contenu peut changer au cours de
l‟exécution d‟un programme.
I.8.2 Déclaration d’une variable : en C on déclare une variable en suivant la syntaxe
suivante : type de la variable nom de la variable ;
Exemple : int A déclaration d‟une variable nommée A de type entier.
I.8.3 Initialisation d’une variable : initialiser une variable c‟est la déclarer en attribuant une
valeur. La syntaxe est la suivante : type de la variable nom de la variable=valeur ;
Exemple : int A=5 ; float b=2.36 ; char p=‟O‟ ;
I.9) NOTION DE CONSTANTE
I.9.1 Définition : une constante est un objet dont le contenu est invariable pendant l‟exécution
du programme.
On distingue deux types de constantes en C : les constantes littérales et les constantes
symboliques
I.9.2 Déclaration d’une constante littérale
Une constante littérale est une valeur qui est introduite directement dans le code source.
En C on déclare une constante littérale en suivant la syntaxe suivante :
const type de la constante nom de la constante=valeur;
Exemple const int A=6 ; const char t=‟G‟ ;
Une constante symbolique est une constante représentée par un nom (symbole) dans votre
programme. Comme la constante littérale, cette constante symbolique ne peut changer.
En C on déclare une constante symbolique en suivant la syntaxe suivante :
#define NOMCONST valeur
Exemple #define PI 3.1459
I.10 STEUCTURE D’UN PROGRAMME EN C
Un programme en C est généralement structuré de la manière suivante :
a) Les directives de préprocesseur ou bibliothèque

b) Le programme principal

c) Le début du programme principal

d) Les instructions du programme

9
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

e) La fin du programme
I.10.1 Détail de la structure
a) Les directives du préprocesseur ou bibliothèques : sont des lignes spéciales
commençant par le symbole (#), placées en haut de tout programme en C et contenant des
fonctions prédéfinies que l‟on utilise dans nos programmes.
La bibliothèque principale en C est la bibliothèque stdio.h. Cette bibliothèque contient les
fonctions d‟entrées-sorties principales.
a.1) Fonctions de la Bibliothèque math.h :
La bibliothèque math.h contient les fonctions mathématiques prédéfinies utilisables par les
programmeurs. Voici un tableau des fonctions essentielles de cette bibliothèque.
Fonctions Symbole Exemple
Valeur absolue Fabs() Fabs(-5)=5
Arrondi au premier nombre Ceil() Ceil(52.7)=53
entier supérieur
Arrondi à la partie entière Floor() Floor(52.7)=52
d‟un nombre
Puissance d‟un nombre Pow(n,p) Pow(2,3)=2^3=8
Racine carrée Sqrt() Sqrt(9)=3
Exponentielle d‟un nombre Exp() Exp(2.7)=1
Logarithme népérien d‟un Log() Log(1)=0
nombre
Logarithme à la base 10 Log10() Log10(10)=1
Sinus d‟un angle en radian Sin() Sin(0)=0
Cosinus d‟un angle en radian Cos() Cos(0)=1
Tangente d‟un angle en Tan() Tan(0)=0
radian
Arc Tangente d‟un angle en atan() atan(0)=0
radian
Arc Cosinus d‟un angle en acos() acos(1)=0
radian
Arc Sinus d‟un angle en asin() asin(0)=0
radian

b) le programme principal : est la fonction principale nommée (main()) qui reçoit toutes les
instructions à exécuter par le programme.
c) le début du programme : en C, le début du programme est désigné par une accolade
ouvrante ({).
d) les instructions du programme : est l‟ensemble des actions exécutées par le programme
(les déclarations, les calculs, la lecture et l‟affichage des variables, etc).
e) la fin du programme : En C, la fin du programme est désignée par une accolade fermante
(}).
En résumant les détails de cette structure, on aura un squelette :
a) #include <stdio.h> --> inclusion de la bibliothèque principale
b) Main() --> le programme principale
c) { --> début du programme
d) Les instructions (déclarations, calculs, affichage et lecture des variables)

10
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

e) } --> La fin du programme


I.11 LES ENTREES-SORTIES CONVERSATIONNELLES
I.11.1 La fonction d’écriture
La fonction principale d‟écriture en C est la fonction printf. Cette fonction a deux rôles :
- Afficher du texte : pour afficher du texte avec la fonction printf, on utilise la syntaxe
suivante :
printf(‘‘le texte à afficher’’) ;
exemple : printf(„„Bonjour la classe‟‟) ; affiche à l‟écran le texte « bonjour la classe »
- Afficher le contenu d’une variable : pour afficher le contenu d‟une variable avec la
fonction printf, on utilise la syntaxe suivante :
printf(‘‘format d’impression à afficher’’, le nom de la variable à afficher) ;
exemple : int A=5 ; printf(„„%d‟‟,A) ; (%d est le format d‟impression du type entier et A est
le nom de la variable)
N.B : a) on peut également afficher à la fois du texte et le contenu d’une variable :
dans ce cas la syntaxe serais :
printf(‘‘texte + format d’impression de la variable’’, nom de la variable) ;
exemple : int A=5 ;
printf(„„la valeur à afficher est %d‟‟,A) ;  ceci affiche à l‟écran « la valeur à afficher est 5 »
b) On peut aussi afficher le contenu de plusieurs variables dans la fonction printf.
Exemple : int i=6 ; float j=0.23; char s=„T‟;
printf(„„Les valeurs à afficher sont: %d %f %c‟‟,i,j,s);
c ) L’utilisation des caractères non imprimables est possible dans la fonction printf
Exemple : printf(„„ je suis heureux d‟apprendre le C\n‟‟)  permet d‟aller à la ligne après
l‟affichage du texte.
I.11.2 La fonction puts : elle permet d‟afficher seulement du texte avec un retour à la ligne
automatique. Donc cette fonction ne peut pas afficher le contenu d‟une variable avec les types
de base. Sa syntaxe est : puts(„„Le texte à afficher‟‟)
Exemple : puts(„„Je suis heureux d‟apprendre le C‟‟) ;  affiche à l‟écran « Je suis heureux
d‟apprendre le C ».
I.11.3 La fonction putchar :
Cette fonction permet d‟afficher le contenu d‟une seule variable de type char. Donc
putchar(A) joue le même rôle que printf(‟‟%c‟‟,A) ;
I.11.4 Les fonctions de lecture : la fonction principale de lecture est la fonction scanf. Cette
fonction permet de lire au clavier le contenu d‟une variable à travers son format d‟impression.
Elle a pour syntaxe :
scanf(’’format d’impression de la variable à lire’’,&nom de la variable à lire) ;
Exemple : int A ;
printf(‟‟Donner une valeur‟‟) ;
scanf(‟‟%d‟‟,&A) ; lecture au clavier du contenu de la variable A.
On a la possibilité de lire à la fois le contenu de plusieurs variables de même type ou pas dans
la fonction scanf.
Exemple : int A ; float B ; char C ;
scanf(‟‟%d %f %c‟‟,&A,&B,&C) ;

11
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

La chaîne de contrôle ou format d‟impression indique le format dans lequel les données lues
sont converties. Elle ne contient pas d'autres caractères (notamment pas de \n).
Comme pour printf, les conversions de format sont spécifiées par un caractère précédé du
signe %.
I.11.5 La fonction getchar : cette fonction permet de lire le contenu d‟une seule variable de
type char. Donc quand on écrit : A=getchar() ; joue le même rôle que scanf(‟‟%c‟‟,&A).
I.12 LES STRUCTURES DE CONTROLE
On appelle instruction de contrôle toute instruction qui permet de contrôler le fonctionnement
d'un programme.
I.12.1) La structure Conditionnelle
I.12.1.1 Blocs d'instructions
Un bloc est une suite d'instructions placées entre { et }.
Un bloc peut se réduire à une seule instruction, voire être "vide". Voici deux exemples de
blocs corrects :
{}
{i=1;}

I.12.1.2 La structure conditionnelle simple


Syntaxe :

if (expression)
{instruction;}
Expression logique encore appelée expression booléen, est une expression à résultat
booléen.
Instuction : représente une ou plusieurs actions.
I.12.1.3 Exemple
Ecrire un algorithme qui accorde une remise de 5% si la somme des achats dépasse 100F

#include<stdio.h>
#define R 0.05
Void main()
{ double Sa
Printf(“Donner la somme des achats”)
Scanf(„‟%lf‟‟,&Sa) ;
If(Sa>100)
Sa=Sa*(1-R)
Printf(„‟La somme est :%lf FG\n „‟,Sa)
}
I.12.1.2 La structure conditionnelle complète
La structure conditionnelle simple nous a permis d‟exécuter un certain nombre d‟action
lorsque la condition est vraie mais rien n‟a été dit dans le cas où la condition est fausse.
La structure alternative complète quant à elle s‟intéresse aux deux cas c‟est-à-dire l‟ensemble
des actions à exécuter lorsque la condition est vraie et l‟ensemble des actions à exécuter
lorsqu‟elle ne l‟est plus.
a) Syntaxe :
If(expression)
{instruction1}
Else
{instruction2}

12
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

b) Exemple :
Un permis de conduire est accordé à tout chauffeur dont le nombre de points est supérieur ou
égal à 120. Rédige un algorithme de ce travail.

#include<studio.h>
Void main()
{int point ;
Printf(‘’Donnez le nombre de points\n’’) ;
Scanf(‘’%d’’,&point) ;
If(point>100)
Printf(‘’Admis’’) ;
else printf(‘’Echec’’) ;}

Remarque important: on construit le bloc d‟instructions lorsqu‟il y a plusieurs actions entre


le if et le else. Il en est de même pour le else.
Exemple : écrire un programme de la résolution d‟une équation du 1er degré dans R.
#include<studio.h>
Void main( )
{ float a,b,x;
Printf(‘’Saisir les coefficients de l’équation’’)
Scanf(‘’ %f%f ’’,&a,&b)
If(a)
{ x=-b/a
Printf(‘’X=%2.3f\n’’,x)
}
Else
Printf(‘’Pas de solution dans R’’)
}
I.12.1.3 La structure conditionnelle emboîtée
a) Syntaxe :
if(expr1)
instruction1 ;
else if(expr2)
instruction2
……………..
Else if(exprn)
Instruction n
b) exemple
Voici un exemple d'utilisation de if imbriqués. Il s'agit d'un programme de
facturation avec remise. Il lit en donnée un simple prix hors taxes et calcule le prix
TTC correspondant (avec un taux de TVA constant de 18,6%). Il établit ensuite
une remise dont le taux dépend de la valeur ainsi obtenue, à savoir :
0 % pour un montant inférieur à 1 000 F
1 % pour un montant supérieur ou égal à 1 000 F et inférieur à 2 000 F
3 % pour un montant supérieur ou égal à 2 000 F et inférieur à 5 000 F
5 % pour un montant supérieur ou égal à 5 000 F
Ce programme est accompagné de deux exemples d'exécution.

13
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

#include<stdio.h>
#define TAUX_TVA 18.6
main()
{
double ht, ttc, net, tauxr, remise ;
printf("donnez le prix hors taxes : ") ;
scanf ("%lf", &ht) ;
ttc = ht * ( 1. + TAUX_TVA/100.) ;
if ( ttc < 1000.) tauxr = 0 ;
else if ( ttc < 2000 ) tauxr = 1. ;
else if ( ttc < 5000 ) tauxr = 3. ;
else tauxr = 5. ;
remise = ttc * tauxr / 100. ;
net = ttc - remise ;
printf ("prix ttc %10.2lf\n", ttc) ;
printf ("remise %10.2lf\n", remise) ;
printf ("net à payer %10.2lf\n", net) ;
}
___________________________________________
donnez le prix hors taxes : 500
prix ttc 593.00
remise 0.00
net à payer 593.00
___________________________________________
donnez le prix hors taxes : 4000
prix ttc 4744.00
remise 142.32
net à payer 4601.68

I.12.2) L’instruction Switch


Sa forme la plus générale est celle-ci :
switch (expression)
{
case constante1:
liste d'instructions 1
break;
case constante2:
liste d'instructions 2
break;
...
case constanteN:
liste d'instructions N
break;
default:
liste d'instructions M
break;
}
Si la valeur de expression est égale à l'une des constantes, la liste d'instructions correspondant
est exécutée.
Sinon la liste d'instructions M correspondant à default est exécutée. L'instruction default est
facultative.
14
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

I.12.2.1) Exemple
Voyez ce premier exemple de programme accompagné de trois exemples d'exécution.
main()
{ donnez un entier : 0
int n ; nul
printf ("donnez un entier : ") ; au revoir
scanf ("%d", &n) ; _________
switch (n)
{ case 0 : printf ("nul\n") ;
donnez un entier : 2
break ; deux
case 1 : printf ("un\n") ; au revoir
break ;
case 2 : printf ("deux\n") ; _________
break ;
} donnez un entier : 5
printf ("au revoir\n") ;
} au revoir
L‟instruction break demande en fait de sortir du bloc. Notez bien que le rôle de cette
instruction est fondamental. Voyez, à titre d'exemple, ce que produirait ce même programme
en l'absence d'instructions break :
_______________________________________
main()
{ donnez un entier : 0
int n ; nul
printf ("donnez un entier : ") ; un
scanf ("%d", &n) ; deux
au revoir
switch (n)
{case 0 : printf ("nul\n") ; _______
case 1 : printf ("un\n") ;
case 2 : printf ("deux\n") ; donnez un entier : 2
} deux
printf ("au revoir\n") ;
au revoir
}
I.12.3) LES BOUCLES
Les boucles permettent de répéter une série d'instructions tant qu'une certaine condition n'est
pas vérifiée.
I.12.3.1) La Boucle « while »
La syntaxe de while est la suivante :
while (expression )
{instructions}
Tant que expression est vérifiée (i.e., non nulle), instruction est exécutée. Si expression est
nulle au départ, instruction ne sera jamais exécutée.
instruction peut évidemment être une instruction composée.
Par exemple, le programme suivant imprime les entiers de 1 à 9.

15
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

i = 1;
while (i < 10)
{
printf("\n i = %d",i);
i++;
}
I.12.3.2) La Boucle « do---while »
Il peut arriver que l'on ne veuille effectuer le test de continuation qu'après avoir exécuté
l'instruction. Dans ce cas, on utilise la boucle do---while. Sa syntaxe est :
Do
{
Instruction
}
while (expression );
Ici, instruction sera exécutée tant que expression est non nulle. Cela signifie donc que
instruction est toujours exécutée au moins une fois. Par exemple, pour saisir au clavier un
entier entre 1 et 10 :
int a;
do
{
printf("\n Entrez un entier entre 1 et 10 : ");
scanf("%d",&a);
}
while ((a <= 0) || (a > 10));
I.12.3.3 La Boucle « for »
La syntaxe de for est :
for (expr 1;expr 2 ; expr 3)
{instruction}
Par exemple, pour imprimer tous les entiers de 0 à 9, on écrit :
for(i = 0; i < 10; i++)
printf("\n i = %d",i);
A la fin de cette boucle, i vaudra 10. Les trois expressions utilisées dans une boucle for
peuvent être constituées de plusieurs expressions séparées par des virgules. Cela permet par
exemple de faire plusieurs initialisations à la fois. Par exemple, pour calculer la factorielle
d'un entier, on peut écrire :
int n, i, fact;
for (i = 1, fact = 1; i <= n; i++)
fact *= i;
printf("%d ! = %d \n", n, fact);
On peut également insérer l'instruction fact *= i; dans la boucle for ce qui donne :
int n, i, fact;
for (i = 1, fact = 1; i <= n; fact *= i, i++);
printf("%d ! = %d \n",n,fact);
On évitera toutefois ce type d'acrobaties qui n'apportent rien et rendent le programme
difficilement lisible.

I.13 LES INSTRUCTIONS DE BRANCHEMENT NON CONDITIONNEL


I.13.1 Branchement non conditionnel « break »
On a vu le rôle de l'instruction break; au sein d'une instruction de branchement multiple
switch. L'instruction break peut, plus généralement, être employée à l'intérieur de n'importe

16
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

quelle boucle. Elle permet d'interrompre le déroulement de la boucle, et passe à la première


instruction qui suit la boucle. En cas de boucles imbriquées, break fait sortir de la boucle la
plus interne. Par exemple, le programme suivant :
main()
{
int i;
for (i = 0; i < 5; i++)
{
printf("i = %d\n",i);
if (i == 3)
break;
}
printf("valeur de i a la sortie de la boucle = %d\n",i);
}
imprime à l'écran
i = 0
i = 1
i = 2
i = 3
valeur de i à la sortie de la boucle = 3

I.13.2 Branchement non conditionnel « continue »


L'instruction continue permet de passer directement au tour de boucle suivant, sans exécuter
les autres instructions de la boucle. Ainsi le programme
main()
{
int i;
for(i = 0; i < 5;i++)
{
if(i == 3)
continue;
printf("i = %d\n",i);
}
printf("valeur de i à la sortie de la boucle = %d\n",i);
}
imprime
i = 0
i = 1
i = 2
i = 4
valeur de i à la sortie de la boucle = 5

I.13.3 L'instruction goto


Elle permet classiquement le branchement en un emplacement quelconque du programme.
Voyez cet exemple qui simule, dans une boucle for, l'instruction break à l'aide de l'instruction
goto (ce programme fournit les mêmes résultats que celui présenté comme exemple de
l'instruction break).
main()
{
int i ;
for ( i=1 ; i<=10 ; i++ )

17
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

{ printf ("début tour %d\n", i) ;


printf ("bonjour\n") ;
if ( i==3 ) goto sortie ;
printf ("fin tour %d\n", i) ;
}
sortie : printf ("après la boucle") ;
}
CHAPITRE II LES TABLEAUX
Un tableau est un ensemble fini d'éléments de même type, stockés en mémoire à des adresses
contiguës.
II.1 LES TABLEAUX À UN INDICE
La déclaration d'un tableau à une dimension se fait de la façon suivante :
type nom-du-tableau[nombre-éléments];
où nombre-éléments est une expression constante entière positive.
Par exemple, la déclaration int tab[10]; indique que tab est un tableau de 10 éléments de type
int.
Cette déclaration alloue donc en mémoire pour l'objet tab un espace de 10 × 4 octets
consécutifs.
Pour plus de clarté, il est recommandé de donner un nom à la constante nombre-éléments par
une directive au préprocesseur, par exemple
#define nombre_element 10
On accède à un élément du tableau en lui appliquant l'opérateur []. Les éléments d'un tableau
sont toujours numérotés de 0 à nombre-éléments -1.
Exemple : Le programme suivant imprime les éléments du tableau tab :
#define N 10
main()
{
int tab[N];
int i;
...
for (i = 0; i < N; i++) printf("tab[%d] = %d\n",i,tab[i]);
}
Un tableau correspond en fait à un pointeur vers le premier élément du tableau. Ce pointeur
est constant. Cela implique en particulier qu'aucune opération globale n'est autorisée sur un
tableau. Notamment, un tableau ne peut pas figurer à gauche d'un opérateur d'affectation. Par
exemple, on ne peut pas écrire ``tab1 = tab2;''. Il faut effectuer l'affectation pour chacun des
éléments du tableau. Exemple
#define N 10
main()
{
int tab1[N], tab2[N];
int i;
...
for (i = 0; i < N; i++)
tab1[i] = tab2[i];
}
On peut initialiser un tableau lors de sa déclaration par une liste de constantes de la façon
suivante :
type nom-du-tableau[N] = {constante1,constante2,...,constanteN};
Par exemple, on peut écrire
#define N 4
18
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

int tab[N] = {1, 2, 3, 4};


main()
{
int i;
for (i = 0; i < N; i++)
printf("tab[%d] = %d\n",i,tab[i]);
}
Si le nombre de données dans la liste d'initialisation est inférieur à la dimension du tableau,
seuls les premiers éléments seront initialisés. Les autres éléments seront mis à zéro.
De la même manière un tableau de caractères peut être initialisé par une liste de caractères,
mais aussi par une chaîne de caractères littérale. Notons que le compilateur complète toute
chaîne de caractères avec un caractère nul '\0'. Il faut donc que le tableau ait au moins un
élément de plus que le nombre de caractères de la chaîne littérale.
#define N 8
char tab[N] = "exemple";
main()
{
int i;
for (i = 0; i < N; i++)
printf("tab[%d] = %c\n",i,tab[i]);
}
Lors d'une initialisation, il est également possible de ne pas spécifier le nombre d'éléments du
tableau. Par défaut, il correspondra au nombre de constantes de la liste d'initialisation.
II.1.2 Quelques règles
a) Les éléments de tableau
Un élément de tableau est une lvalue. Il peut donc apparaître à gauche d'un opérateur
d'affectation comme dans : t[2] = 5.
Il peut aussi apparaître comme opérande d'un opérateur d'incrémentation, comme dans :
t[3]++ --t[i]
En revanche, il n'est pas possible, si t1 et t2 sont des tableaux d'entiers, d'écrire t1 = t2 ; en
fait, le langage C n'offre aucune possibilité d'affectations globales de tableaux, comme c'était
le cas, par exemple, en Pascal.
b) Les indices
Un indice peut prendre la forme de n'importe quelle expression arithmétique de type entier
(ou caractère, compte tenu des règles de conversion systématique). Par exemple, si n, p, k et j
sont de type int, ces notations sont correctes :
t[n-3]
t[3*p-2*k+j%l]
Il en va de même, si c1 et c2 sont de type char, de :
t[c1+3]
t[c2-c1]
c) La dimension d'un tableau
La dimension d'un tableau (son nombre d'éléments) ne peut être qu'une constante ou une
expression constante. Ainsi, cette construction :
#define N 50
.....
int t[N] ;
float h[2*N-1] ; est correcte.
Elle ne le serait pas, par contre, si N était une constante symbolique définie par const int N =
50 (les expressions N et 2*N-1 n'étant alors plus calculables par le compilateur).

19
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

d) Débordement d'indice
Aucun contrôle de "débordement d'indice" n'est mis en place par la plupart des compilateurs.
Pour en comprendre les conséquences, il faut savoir que, lorsque le compilateur rencontre une
lvalue telle que t[i], il en détermine l'adresse en ajoutant à l'adresse de début du tableau t, un
"décalage" proportionnel à la valeur de i (et aussi proportionnel à la taille de chaque élément
du tableau). De sorte qu'il est très facile (si l'on peut dire !) de désigner et, partant, de
modifier, un emplacement situé avant ou après le tableau.
II.2) LES TABLEAUX À PLUSIEURS INDICES
II.2.1) Déclaration
Comme tous les langages, C autorise les tableaux à plusieurs indices (on dit aussi à plusieurs
dimensions).
Par exemple, la déclaration :
int t[5][3] réserve un tableau de 15 (5 x 3) éléments. Un élément quelconque de ce tableau se
trouve alors repéré par deux indices comme dans ces notations : t[3][2] t[i][j] t[i-3][i+j]
Notez bien que, là encore, la notation désignant un élément d'un tel tableau est une lvalue.
Aucune limitation ne pèse sur le nombre d'indices que peut comporter un tableau. Seules les
limitations de taille mémoire liées à un environnement donné risquent de se faire sentir.
II.2.2 Initialisation de tableaux à plusieurs indices
Voyez ces deux exemples équivalents (nous avons volontairement choisi des valeurs
consécutives pour qu'il soit plus facile de comparer les deux formulations) :
int tab [3] [4] = { { 1, 2, 3, 4 } ,{ 5, 6, 7, 8 },{ 9,10,11,12 } }
int tab [3] [4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
La première forme revient à considérer notre tableau comme formé de trois tableaux de quatre
éléments chacun. La seconde, elle, exploite la manière dont les éléments sont effectivement
rangés en mémoire et elle se contente d'énumérer les valeurs du tableau suivant cet ordre.
Cette fois encore, certaines valeurs peuvent être omises. Par exemple, les deux déclarations
suivantes sont équivalentes :
int tab [3] [4] = { { 1, , 2 } , , { 3, 4, , 5 } }
int tab [3] [4] = { 1, , 2, , , , , 3, 4, , 5 }

CHAPITREIII : LES FONCTIONS


Comme tous les langages, C permet de découper un programme en plusieurs parties nommées
souvent modules. Cette programmation dite modulaire se justifie pour de multiples raisons :
- Un programme écrit d'un seul tenant devient difficile à comprendre dès qu'il dépasse une ou
deux pages de texte. Une écriture modulaire permet de le scinder en plusieurs parties et de
regrouper dans le "programme principal" les instructions en décrivant les enchaînements.
Chacune de ces parties peut d'ailleurs, si nécessaire, être décomposée à son tour en modules
plus élémentaires ; ce processus de décomposition pouvant être répété autant de fois que
nécessaire, comme le préconisent les méthodes de programmation structurée.
- La programmation modulaire permet d'éviter des séquences d'instructions répétitives, et cela
d'autant plus que la notion d'argument permet de paramétrer certains modules.
- La programmation modulaire permet le partage d'outils communs qu'il suffit d'avoir écrits et
mis au point une seule fois. Cet aspect sera d'autant plus marqué que C autorise effectivement
la compilation séparée de tels modules.
III.1 - LA FONCTION : LA SEULE SORTE DE MODULE EXISTANT EN C
En C, il n'existe qu'une seule sorte de module, nommé fonction.
Définition Une fonction est un bloc de code C indépendant, référencé par un nom, qui réalise
une tâche précise et qui peut renvoyer une valeur au programme qui l‟a appelée.

20
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

* Une fonction est référencée par un nom. Ce nom est unique et en l‟introduisant dans le
source de votre programme, vous pouvez exécuter le code de la fonction. Une fonction peut
être appelée par une autre fonction.
* Une fonction est indépendante. Une fonction peut effectuer sa tâche avec ou sans échanges
avec une autre partie du programme.
* Une fonction réalise une tâche particulière. La tâche est l‟unité de base du travail réalisé par
le programme. Cela peut être l‟envoi d‟une ligne de texte vers l‟imprimante, un tri, ou le
calcul d‟une racine carrée.
* Une fonction peut renvoyer une valeur au programme appelant. Quand ce programme
appelle la fonction, le code de cette fonction est exécuté. Ces instructions peuvent renvoyer
une information au programme.
III.2 DECLARATION ET DEFINITION D’UNE FONCTION
Le format général d‟une définition de fonction est de la forme :
type_resultat nom fonction (type1 arg1, . . . , typen argn)
{
<déclaration de variables locales >
<liste d’instructions >
}
Dans cette définition de fonction, on rappelle que:
– type_resultat correspond au type du résultat de la fonction.
– nom fonction est le nom qui identifie la fonction.
– type1 arg1 . . .typen argn définit les types et les noms des paramètres de
la fonction. Ces arguments sont appelés paramètres formels, par opposition
aux paramètres effectifs qui sont les paramètres avec lesquels la fonction est
effectivement appelée.
On peut se contenter de déclarer le prototype d‟une fonction (sans le corps) :
type_resultat nom fonction (type1 arg1, . . . , typen argn) ;
Dans ce cas, la définition de la fonction (avec le corps des instructions qui la compose) peut
être déclarée plus loin dans le programme.
Contrairement à la définition de la fonction, le prototype n‟est donc pas suivi
du corps de la fonction (contenant les instructions à exécuter).
ATTENTION ! Le prototype est une instruction, il est donc suivi d‟un point-virgule !
Exemple : Ce programme emploie une fonction utilisateur pour calculer le cube d’un
nombre
/* Exemple d’une fonction simple */
#include <stdio.h>
#include <stdlib.h>
long cube(long x);
long input, reponse;
int main()
{
printf("Entrez une valeur entière : ");
scanf("%d", &input);
reponse = cube(input);
printf("\n\n Le cube de %ld est %ld\n.", input, reponse);
}
long cube(long x)
{
long x_cube;
x_cube = x * x * x;

21
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

return x_cube;
}
III.3 Appel d’une fonction
L‟appel d‟une fonction se fait par l‟expression:
nom fonction (arg1, . . . ,argn )
L‟ordre et le type des paramètres effectifs de la fonction doivent concorder avec
ceux donnés dans la définition de l‟en-tête de la fonction. Les paramètres effectifs peuvent
être des expressions.
De plus, l‟ordre d‟évaluation des paramètres effectifs n‟est pas assuré et dépend
du compilateur. Il est donc déconseillé, pour une fonction à plusieurs paramètres, de faire
figurer des opérateurs d‟incrémentation ou de décrémentation (++ ou --) dans les expressions
définissant les paramètres effectifs.
III.4 Exemple d’utilisation d’une fonction
Nous vous proposons d'examiner tout d'abord un exemple simple de fonction correspondant à
l'idée usuelle que l'on se fait d'une fonction, c'est-à-dire recevant des arguments et fournissant
une valeur.

#include <stdio.h>
/***** le programme principal (fonction main) *****/
main()
{
float fexple (float, int, int) ; /* déclaration de fonction
fexple */
float x = 1.5 ;
float y, z ;
int n = 3, p = 5, q = 10 ;
/* appel de fexple avec les arguments x, n et p */
y = fexple (x, n, p) ;
printf ("valeur de y : %e\n", y) ;
/* appel de fexple avec les arguments x+0.5, q et n-1 */
z = fexple (x+0.5, q, n-1) ;
printf ("valeur de z : %e\n", z) ;
}
/*************** la fonction fexple ****************/
float fexple (float x, int b, int c)
{ float val ; /* déclaration d'une variable "locale" à fexple
val = x * x + b * x + c ;
return val ;
}
III.5 Portée des variables
Selon l‟endroit où on déclare une variable, celle-ci pourra être accessible (visible)
partout dans le code ou seulement dans une partie de celui-ci (à l‟intérieur d‟une
fonction typiquement), on parle de la portée (ou visibilité) de la variable.
Lorsqu‟une variable est déclarée dans le code même, c‟est-à-dire à l‟extérieur
de toute fonction ou de tout bloc d‟instruction, elle est accessible de partout
dans le code (n‟importe quelle fonction du programme peut faire appel à cette
variable). On parle alors de variable globale.

22
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Lorsque l‟on déclare une variable à l‟intérieur d‟un bloc d‟instructions (entre des
accolades), sa portée se limite à l‟intérieur du bloc dans lequel elle est déclarée.
On parle de variable locale.
III.5.1 Les variables Globales
Nous avons vu comment échanger des informations entre différentes fonctions grâce à la
transmission d'arguments et à la récupération d'une valeur de retour.
En fait, en C comme en Pascal, plusieurs fonctions (dont, bien entendu le programme
principal main) peuvent partager des variables communes qu'on qualifie alors de globales

Exemple :
#include <stdio.h>
int i ;
main()
{ void optimist (void) ;
for (i=1 ; i<=5 ; i++)
optimist() ;
}
void optimist(void)
{ printf("il fait beau %d fois\n", i);
}
La variable i a été déclarée en dehors de la fonction main. Elle est alors connue de toutes les
fonctions qui seront compilées par la suite au sein du même programme source. Ainsi, ici, le
programme principal affecte à i des valeurs qui se trouvent utilisées par la fonction optimist.
Notez qu'ici la fonction optmist se contente d'utiliser la valeur de i mais rien ne l'empêche de
la modifier. C'est précisément ce genre de remarque qui doit vous inciter à n'utiliser les
variables globales que dans des cas limités. En effet, toute variable globale peut être modifiée
insidieusement par n'importe quelle fonction. Lorsque vous aurez à écrire des fonctions
susceptibles de modifier la valeur de certaines variables, il sera beaucoup plus judicieux de
prévoir d'en transmettre l'adresse en argument (comme vous apprendrez à le faire dans le
prochain chapitre). En effet, dans ce cas, l'appel de la fonction montrera explicitement quelle
est la variable qui risque d'être modifiée et, de plus, ce sera la seule qui pourra l'être.
III.5.2 Les Variables Locales
A l'exception de l'exemple du paragraphe précédent, les variables que nous avions rencontrées
jusqu'ici n'étaient pas des variables globales. Plus précisément, elles étaient définies au sein
d'une fonction (qui pouvait être main). De telles variables sont dites "locales" à la fonction
dans laquelle elles sont déclarées.
III.5.2.1 La portée des variables locales
Les variables locales ne sont "connues" qu'à l'intérieur de la fonction où elles sont déclarées.
Leur portée est donc limitée à cette fonction.
Les variables locales n'ont aucun lien avec des variables globales de même nom ou avec
d'autres variables locales à d'autres fonctions. Voyez cet exemple :
int n ;
main()
{
int p ;
....
}
fct1 ()
{
int p ;

23
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

int n ;
}
La variable p de main n'a aucun rapport avec la variable p de fct1. De même, la variable n de
fct1 n'a aucun rapport avec la variable globale n. Notez qu'il est alors impossible, dans la
fonction fct1, d'utiliser cette variable globale n.
III.7 PASSAGE DE PARAMETRES A UNE FONCTION
Les paramètres ou arguments sont les boîtes aux lettres d‟une fonction. Elles
acceptent les données de l‟extérieur et déterminent les actions et le résultat de
la fonction.
III.7.1 Passage par valeur
En C, le passage des paramètres se fait toujours par valeur, autrement dit les fonctions
n‟obtiennent que les valeurs de leurs paramètres et n‟ont pas d‟accès aux variables elles-
mêmes.
Les paramètres d‟une fonction sont à considérer comme des variables locales qui sont
initialisées automatiquement par les valeurs indiquées lors d‟un appel.
A l‟intérieur de la fonction, On peut donc changer les valeurs des paramètres sans influencer
les valeurs originales dans les fonctions appelantes.
Exemple :
La fonction ETOILES dessine une ligne de N étoiles. Le paramètre N est modifié à l‟intérieur
de la fonction mais pas à l‟extérieur :
#include <stdio.h>
void ETOILES(int N)
{
while (N>0)
{
printf("*");
N--;
}
printf("\n");
}
int main() {
int compteur=14;
ETOILES(compteur);
printf("Valeur de compteur: %i\n",compteur);
return 0;
}
L‟appel de ce programme renvoit :
**************
Valeur de compteur: 14
La valeur de compteur n‟a donc pas été modifiée par l‟appel de la fonction ETOILES.
III.7.2 Passage des paramètres par adresse
Comme on vient de le voir, tout paramètre est passé par valeur, et cette règle ne souffre
aucune exception. Cela pose le problème de réaliser un passage de paramètre par adresse
lorsque le programmeur en a besoin.
Pour changer la valeur d‟une variable de la fonction appelante, on procède
comme suit:
– la fonction appelante doit fournir l‟adresse de la variable ;
– la fonction appelée doit déclarer le paramètre comme pointeur.
On peut alors atteindre la variable à l‟aide du pointeur.
Exemple : Supposons qu‟on désire écrire une procédure add, admettant trois paramètres a, b

24
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

et c. On désire que le résultat de l‟exécution de add soit d‟affecter au paramètre c la somme


des valeurs des deux premiers paramètres.
Le paramètre c ne peut évidemment pas être passé par valeur, puisqu‟on désire
modifier la valeur du paramètre effectif correspondant. Il faut donc programmer
add de la manière suivante :
void add(int a, int b, int *c)
{
/* c repère l‟entier où on veut mettre le résultat */
*c = a + b;
}
int main()
{
int i=10, j=14,k;
/* on passe les valeurs de i et j comme premiers paramètres */
/* on passe l‟adresse de k comme troisième paramètre */
add(i,j,&k);
}
III.7.3 Passage de tableau en paramètre
Comme il est impossible de passer la valeur de tout un tableau a une fonction,
on fournit l‟adresse d‟un élément du tableau.
En général, on fournit l‟adresse du premier élément du tableau, qui est donnée
par le nom du tableau.
Dans la liste des paramètres d‟une fonction, on peut déclarer un tableau par le
nom suivi de crochets,
<type> <nom>[]
ou simplement par un pointeur sur le type des éléments du tableau :
<type> *<nom>
On préfèrera la première écriture car il n‟est pas possible dans la seconde de
savoir si le programmeur a voulu passer en paramètre un pointeur vers <type>
(c‟est à dire un pointeur vers un seul <type>), ou au contraire si il a voulu
passer un tableau, c‟est à dire un pointeur vers une zone de n <type>.
Exemple :

#include <stdlib.h>
/* Initialise les éléments d’un tableau */
void init_tab (int tab[], int n)
{
int i;
for (i = 0; i < n; i++)
tab[i] = i;
return;
}
int main()
{
int i, n = 5;
int *tab;
tab = (int*)malloc(n * sizeof(int));
init(tab,n);
}

25
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Remarque : Quand une fonction admet un paramètre de type tableau, il y a


deux cas possibles :
1. soit les différents tableaux qui lui sont passés en paramètre effectif ont des
tailles différentes, et dans ce cas la taille doit être un paramètre supplémentaire de la fonction,
comme dans l‟exemple précédent ;
2. soit les différents tableaux qui lui sont passés en paramètre effectif ont
tous la même taille, et dans ce cas la taille peut apparaître dans le type
du paramètre effectif : #define NB_ELEM 10
void init_tab (int tab[NB_ELEM])
{
...
}

CHAPITRE IV : LES POINTEURS


IV.1 INTRODUCTION
Toute variable manipulée dans un programme est stockée quelque part en mémoire centrale.
Cette mémoire est constituée d‟octets qui sont identifiés de manière univoque par un numéro
qu‟on appelle adresse comme l‟illustre la figure ci-dessous :

Illustration de l’adressage de la mémoire centrale

Par analogie, on peut voir la mémoire centrale comme une armoire constituée
de tiroirs numérotés. Un numéro de tiroir correspond à une adresse.

26
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Ainsi, lorsqu‟on déclare une variable var de type T, l‟ordinateur réserve un


espace mémoire (de sizeof(T) octets) pour y stocker les valeurs de var.
Pour retrouver cette variable, il suffit donc de connaître l‟adresse du premier
octet ou elle est stockée (ou, s‟il s‟agit d‟une variable qui recouvre plusieurs
octets contigus, l‟adresse du premier de ces octets).

Un pointeur est une variable qui contient l‟adresse d‟une autre variable.

IV.2 Intérêt des Pointeurs

Les pointeurs présentent de nombreux avantages:


– Ils permettent de manipuler de façon simple des données de taille importante (comme les
tableaux, les structures etc...). Ainsi, au lieu de passer en paramètre à une fonction un élément
très grand (en taille), on pourra se contenter de lui fournir un pointeur vers cet élément... On
gagne évidemment alors en efficacité dans l‟exécution du programme.
– Comme on a vu au chapitre 2, les tableaux ne permettent de stocker qu‟un
nombre fixé d‟éléments de même type. Si les composantes du tableau sont des
pointeurs, il sera possible de stocker des éléments de tailles diverses (comme
des chaînes de caractères :
– Il est possible de créer des structures chaînées (on dit aussi structures auto référées) qui sont
utilisées pour définir des listes chainées. De telles listes sont beaucoup utilisées en
programmation (le nombre d‟éléments de cette liste peut évoluer dynamiquement, ce qui
permet une utilisation plus souple que celle des tableaux).

IV.3 Déclaration des pointeurs

En C, chaque pointeur est limité à un type de donnée. En effet, même si la


valeur d‟un pointeur (une adresse) est toujours un entier (ou éventuellement
un entier long), le type d‟un pointeur dépend du type de l‟objet pointé.

On déclare un pointeur par l‟instruction :


type *nom-du-pointeur ;
où type est le type de l‟objet pointé.

Exemple :
int *pi; // pi est un pointeur vers un int
short int *psi; // psi est un pointeur vers un short int
char *pc; // pc pointeur vers un char.

A noter aussi l‟existence de pointeurs génériques, c‟est à dire capable de pointer


vers n‟importe quel type d‟objet. On utilise pour cela le type void *.
Sans un tel type, il ne serait pas possible par exemple d‟indiquer le type d‟objet
rendu par les fonctions d‟allocation de mémoire qui rendent un pointeur vers
l‟objet alloué, puisque ce type varie d‟une invocation à l‟autre de la fonction.
Par exemple, la fonction malloc de la bibliothèque standard est définie de la
manière suivante : void *malloc(size_t size);

27
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

IV.4 Opérateur de manipulation des pointeurs

Lors du travail avec des pointeurs, nous avons besoin :


– d‟un opérateur ’adresse de’ & pour obtenir l‟adresse d‟une variable.
– d‟un opérateur ’contenu de’ * pour accéder au contenu d‟une adresse.

IV.4.1 L’opérateur ’adresse de’ &


L‟opérateur & permet d‟accéder à l‟adresse d‟une variable. La syntaxe est la
suivante : &nom-variable
Cette adresse peut alors être utilisée pour initialiser la valeur d‟un pointeur.
Dans l‟exemple suivant, on définit un pointeur p qui pointe vers un entier i :
int * p; // étape (1): pointeur vers un entier non initialisé
int i = 14; // étape (2): variable entière initialisée à 14
p=&i; // étape (3): p pointe vers i

Les différentes étapes de ce scénario sont illustrées dans la figure ci-dessous :

L‟opérateur & peut seulement être appliqué à des objets qui se trouvent dans
la mémoire interne, c‟est à dire à des variables et des tableaux. Il ne peut pas
être appliqué à des constantes ou des expressions.

IV.4.2 L’opérateur ’contenu de’ : *

L‟opérateur unaire d‟indirection * permet d‟accéder directement à la valeur de


l‟objet pointé (on dit qu‟on déréférence un pointeur). La syntaxe est la suivante :
*nom-pointeur
Ainsi, si p est un pointeur vers un entier i, *p désigne la valeur de i. Exemple :
int main()

{
int i = 14;
int *p;
p = &i; //p contient l‟adresse de i (0x352C)
printf("*p = %d \n",*p); //affiche "*p = 14"
}
Pour résumer, après les instructions précédentes :
– i désigne le contenu de i (soit 14)
– &i désigne l‟adresse de i (soit 0x352C)

28
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

– p désigne l‟adresse de i (soit 0x352C)


– *p désigne le contenu de i (soit 14)
En outre : &p désigne l‟adresse de p (soit 0x1A30)
– *i est en général illégal (puisque i n‟est pas un pointeur mais il peut arriver
que la valeur *i ait un sens).

IV.5 Initialisation d’un pointeur


Par défaut, lorsque l‟on déclare un pointeur p sur un objet de type T, on ne
sait pas sur quoi il pointe. En effet, la case mémoire qu‟il occupe contient une
certaine valeur qui risque de le faire pointer vers une zone hasardeuse de la
mémoire.
Comme toute variable, un pointeur doit être initialisé !
Cette initialisation peut s‟effectuer de trois façons:
1. Affectation à l‟adresse d‟une autre variable de p. Si la variable est un pointeur, on peut faire
l‟affectation directement, sinon on doit utiliser l‟opérateur &.

Exemple :
int *p1, *p2;//déclaration de 2 pointeurs vers des entiers
int i = 14; //supposons que i se trouve à l‟adresse 0x352C
p1 = &i; //affectation à l‟adresse de i de p1 , soit 0x352C
p2 = p1; //affectation de p2 à p1:
//p2 contient aussi l‟adresse de i
2. Affectation de p à la valeur NULL : on peut dire qu‟un pointeur ne pointe
sur rien en lui affectant la valeur NULL (cette valeur est définie dans le
fichier stddef.h). Exemple :
int * p = NULL;
3. affectation directe de *p (la zone mémoire pointée par p). Pour cela, il faut d‟abord réserver
à *p un espace-mémoire de taille adéquate (celui du type pointé par p, soit sizeof(T) octets).
L‟adresse de cet espace-mémoire sera la valeur de p. Cette opération consistant à réserver un
espace-mémoire pour stocker l‟objet pointé s‟appelle une allocation dynamique.
Pour bien montrer l‟intérêt de l‟initialisation de tout pointeur, reprenons l‟exemple
précédent dans lequel on remplace l‟affectation p2 = p1 par *p2 = *p1 :
int * p1, *p2;
int i = 14;
p1 = &i;
*p2 = *p1;
Que va- t- il se passer ?

p1 est bien initialisé et pointe sur i (*p1=14)


– mais p2 n‟a pas été initialisé : *p2 désigne une adresse mémoire a priori inconnue.
L‟instruction *p2 = *p1 force l‟écriture de la valeur *p1=14 dans la case mémoire pointée par
p2 ce qui pourrait avoir des conséquences désastreuses

IV.6 Arithmétique des pointeurs


Le pointeur du premier élément d‟un tableau doit être incrémenté d‟un nombre d‟octets égal à

29
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

la taille des données du tableau pour pointer sur l‟élément suivant. Pour pointer sur un
élément quelconque en utilisant une notation de type pointeur, on utilise le pointeur
arithmétique.
a) Incrémenter les pointeurs
Incrémenter un pointeur consiste à en augmenter la valeur. Si vous incrémentez un pointeur
de 1, le pointeur arithmétique va augmenter sa valeur pour qu‟il accède à l‟élément de tableau
suivant. En fait, C connaît le type de donnée du tableau à partir de la déclaration, et il va
incrémenter le pointeur de la taille de cette donnée chaque fois.
Par exemple, si ptr_int pointe sur un élément de tableau de type int, l‟instruction
suivante : ptr_int++; incrémente la valeur de ce pointeur de 4 pour qu‟il pointe sur l‟élément
int suivant.
De la même façon, si vous augmentez la valeur du pointeur de n, C va incrémenter ce pointeur
pour qu‟il pointe sur le n-ième élément suivant :
ptr_int += 2;
Cette instruction va augmenter de 8 la valeur du pointeur, pour qu‟il pointe 2 éléments plus
loin.
b) Décrémenter les pointeurs
La décrémentation des pointeurs suit le même principe que l‟incrémentation. Si vous utilisez
les opérateurs (––) ou (–=) pour décrémenter un pointeur, le pointeur arithmétique va
diminuer sa valeur automatiquement en fonction de la taille des données pointées.
L‟incrémentation du pointeur permet au programme de se déplacer facilement dans le tableau.
c) Exemple d’Utilisation d’un pointeur arithmétique pour accéder aux éléments
d’un tableau
/* Utilisation d’un pointeur arithmétique pour accéder
aux éléments d’un tableau. */
#include <stdio.h>
#include <stdlib.h>
#define MAX 10
/* Déclaration et initialisation d’un tableau d’entiers. */
int i_tableau[MAX] = { 0,1,2,3,4,5,6,7,8,9 };
/* Déclaration d’un pointeur vers int et d’une variable int.
*/
int *i_ptr, count;
/* Déclaration et initialisation d’un tableau de type double.
*/
double d_tableau[MAX] = {.0, .1, .2, .3, .4, .5, .6, .7, .8,
.9};
/* Déclaration d’un pointeur vers double. */
double *d_ptr;
int main()
{
/* Initialisation des pointeurs. */
i_ptr = i_tableau;
d_ptr = d_tableau;
/* Affichage des éléments du tableau. */
for (count = 0; count < MAX; count++)
printf("%d\t%f\n", *i_ptr++, *d_ptr++);
exit(EXIT_SUCCESS);
}

30
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

A noter qu‟on peut également utiliser les opérateurs ++ et -- avec des pointeurs. En général,
on les utilise pour réaliser des parcours de tableaux et plus particulièrement dans les chaînes
de caractères. Exemple (comme on le verra dans le chapitre sur les chaînes de caractères,
toute chaîne se termine par un caractère null, le caractère ‟\0‟) :

Exemple
#include <stdio.h>
int main() {
char * mess = "On est super content!";
char *p;
for (p = &mess[0]; *p != ’\0’; p++) {
printf("Adresse: %ld | Contenu: %c\n",(long)p,*p);
}
// Autre méthode classique, avec while
p = mess; // équivalent de p = &mess[0] dans ce cas
puts("========================================");
while (*p != ’\0’) {
printf("Adresse: %ld | Contenu: %c\n",(long)p,*p);
p++;
}
return 0;
}

IV.7 Pointeurs et tableaux

Comme nous l'avons déjà constaté, le nom d'un tableau représente l'adresse de son premier
élément. En d'autres termes:
&tableau[0] et tableau sont une seule et même adresse.
En simplifiant, nous pouvons retenir que le nom d'un tableau est un pointeur constant sur le
premier élément du tableau, par exemple :
En déclarant un tableau T de type int et un pointeur P sur int,
int T[20];

int *P;
l'instruction:
P = T; est équivalente à P = &T[0];
Si P pointe sur une composante quelconque d'un tableau, alors P+1 pointe sur la composante
suivante. Plus généralement,
P+i pointe sur la i-ième composante derrière P et
P-i pointe sur la i-ième composante devant P.
Ainsi, après l'instruction,
P = T; le pointeur P pointe sur T[0], et
*(P+1) désigne le contenu de T[1]
*(P+2) désigne le contenu de T[2]
...
*(P+i) désigne le contenu de T[i]

31
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

IV.8 Allocation dynamique de mémoire


Nous avons vu que l‟utilisation de pointeurs permet de mémoriser économiquement des
données de différentes grandeurs (puisqu‟on se contente de mémoriser l‟adresse de ces
données). Pour permettre une utilisation efficace de la mémoire, il est primordial de disposer
de moyens pour réserver et libérer de la mémoire dynamiquement au fur et à mesure de
l‟exécution. C‟est ce qu‟on appelle une allocation dynamique de la mémoire. Les fonctions
pour la gestion dynamique de la mémoire sont déclarées dans le fichier stdlib.h (à inclure).
L‟opération consistant à réserver un espace-mémoire est réalisée par la fonction malloc. Sa
syntaxe est : malloc(nb octets).
Cette fonction retourne un pointeur de type char * pointant vers une zone mémoire de nb
octets octets. Pour initialiser des pointeurs vers des objets qui ne sont pas de type char, il faut
convertir le type de la sortie de la fonction malloc à l‟aide d‟un cast (déjà étudié au chap1).
A noter enfin qu‟en pratique, on utilise la fonction sizeof() pour déterminer la valeur nb
octets. Ainsi, pour initialiser un pointeur vers un entier, on écrit :
#include <stdlib.h>
int main() {
int *p;
p = (int*)malloc(sizeof(int)); // allocation dynamique
*p = 14;
}
Il est primordial de bien comprendre qu‟avant l‟allocation dynamique (et
plus généralement avant toute initialisation de p), *p n‟a aucun sens !
En particulier, toute manipulation de la variable *p générerait en général une
violation mémoire, détectable à l‟exécution par le message d‟erreur Segmentation fault.
La fonction malloc permet également d‟allouer un espace pour plusieurs objets contigus en
mémoire. On peut écrire par exemple :
#include <stdlib.h>
#include <stdio.h>
int main() {
int *p;
p = (int*)malloc(2 * sizeof(int)); //allocation pour 2 int
*p = 14;
*(p + 1) = 10;
printf("p = %lx \t *p = %d \t p+1 = %lx \t *(p+1)=%d\n",
(unsigned long)p, *p, (unsigned long)(p+1), *(p+1));
return 0;
}
L‟appel à la fonction malloc a ainsi permis de réserver 8 octets en mémoire (qui permettent de
stocker 2 objets de type int) et d‟affecter à p l‟adresse de cette zone mémoire.
La fonction calloc a le même rôle que la fonction malloc mais elle permet
de réserver nb-objets objets de nb octets octets et de les initialiser à zéro. Sa syntaxe est :
calloc(nb-objets,nb octets)
Ainsi, si p est de type int*, l‟instruction
p = (int*)calloc(N,sizeof(int));

32
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

est sémantiquement équivalente à


p = (int*)malloc(N * sizeof(int));
for (i = 0; i < N; i++)
*(p + i) = 0;
L‟emploi de calloc est simplement plus pratique et plus rapide.

IV.8 Libération dynamique avec la fonction free


Lorsque l‟on n‟a plus besoin de l‟espace-mémoire alloué dynamiquement par
malloc ou calloc (c‟est-`a-dire quand on n‟utilise plus le pointeur p initialisé par ces
fonctions), il faut libérer ce bloc de mémoire. Ceci se fait à l‟aide de l‟instruction free qui a
pour syntaxe :
free(nom-du-pointeur);
Cette instruction libère le bloc de mémoire désigné par nom-du-pointeur mais
n‟a pas d‟effet si le pointeur a la valeur NULL.
A toute instruction de type malloc ou calloc doit être associée une instruction
de type free.
Attention:
– La fonction free peut aboutir à un désastre si on essaie de libérer de la mémoire qui n‟a pas
été allouée par malloc ou calloc.
– free ne change pas le contenu du pointeur.
– Si la mémoire n‟est pas libérée à l‟aide de free, alors elle l‟est automatiquement à la fin du
programme. Cependant, cela ne doit pas dispenser de l‟utilisation de cette fonction.

CHAPITRE V : LES CHAINES DE CARACTERES

V.1 Définition

Il n'existe pas de type spécial chaîne ou string en C. Une chaîne de caractères est traitée
comme un tableau à une dimension de caractères (vecteur de caractères). Il existe quand
même des notations particulières et une bonne quantité de fonctions spéciales pour le
traitement de tableaux de caractères.
Dans un programme informatique, les chaînes de caractères servent à stocker les informations
non numériques comme par exemple une liste de nom de personne ou des adresses.

V.2 DECLARATION D’UNE CHAINE


Une chaîne de caractères est un tableau de type char. La déclaration est identique à un tableau
normal:
char <nom_chaine> [<dimension>]
La représentation interne d'une chaîne de caractères est terminée par le symbole '\0' (NULL).
Ainsi, pour un texte de n caractères, nous devons prévoir n+1 octets.
Malheureusement, le compilateur C ne contrôle pas si nous avons réservé un octet pour le
symbole de fin de chaîne; l'erreur se fera seulement remarquer lors de l'exécution du
programme.

V.3 INITIALISER UNE CHAINE DE CARACTERES


En général, les tableaux sont initialisés par l'indication de la liste des éléments du tableau

33
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

entre accolades:
char MACHAINE[ ] = {'H','e','l','l','o','\0'};
Pour le cas spécial des tableaux de caractères, nous pouvons utiliser une initialisation plus
confortable en indiquant simplement une chaîne de caractères constante:
char MACHAINE[ ] = "Hello";
Lors de l'initialisation par [ ], l'ordinateur réserve automatiquement le nombre d'octets
nécessaires pour la chaîne, c.-à-d.: le nombre de caractères + 1 (ici: 6 octets). Nous pouvons
aussi indiquer explicitement le nombre d'octets à réserver, si celui-ci est supérieur ou égal à la
longueur de la chaîne d'initialisation.

V.4 EXEMPLES D’INITIALISATION


char MACHAINE[ ] = “Hello”;
char MACHAINE[6] = “Hello”;
char MACHAINE[ ] = {„H‟,‟e‟,‟l‟,‟l‟,‟o‟,‟\0‟};
char MACHAINE[8] = “Hello”;
par contre:
char MACHAINE[5] = “Hello”; donnera une erreur à l‟exécution
char MACHAINE[4] = “Hello”; donnera une erreur à la compilation.

Exemple

int main(void)
{
int i=0;
char *pNom;
char Chaine[] = "le chat";
pNom=Chaine; // <=> pNom=&Chaine[0];
while (*pNom!='\0')
{
printf("%c",*pNom);
*pNom++;
}
printf("\n");
// ce qui est équivalent à
while (pNom[i]!='\0')
{
printf("%c",pNom[i]);
i++;
}
printf("\n");
// ou encore
printf("%s\n",pNom);
return 0;
}

V.5 CHAINES DE CARACTERES CONSTANTES

Attention à la déclaration:

34
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Pour la mémorisation de la chaîne de caractères "Hello", C a besoin de six (!!) octets.


'x‟ est un caractère constant, qui a une valeur numérique:
Par exemple: 'x' à la valeur 120 dans le code ASCII.
"x” est un tableau de caractères qui contient deux caractères:
la lettre 'x' et le caractère NUL: '\0'
'x‟ est codé dans un octet
"x” est codé dans deux octets.

Remarque :

* Les chaînes de caractères constantes (string literal) sont indiquées entre guillemets. La
chaîne de caractères vide est alors: ""
* Dans les chaînes de caractères, nous pouvons utiliser toutes les séquences d'échappement
définies comme caractères constants: "Ce \ntexte \nsera réparti sur 3 lignes."
* Le symbole " peut être représenté à l'intérieur d'une chaîne par la séquence d'échappement
\”.
* Le symbole ' peut être représenté à l'intérieur d'une liste de
caractères par la séquence d'échappement \' : {'L','\'','a','s','t','u','c','e','\0'}

* Plusieurs chaînes de caractères constantes qui sont séparées par des signes d'espacement
(espaces, tabulateurs ou interlignes) dans le texte du programme seront réunies en une
seule chaîne constante lors de la compilation:
"un " "deux" " trois” sera évalué à "un deux trois"
=> il est possible de définir de très longues chaînes de caractères constantes en utilisant
plusieurs lignes dans le texte du programme.

V.6 ACCEDER A UNE CHAINE ET A SES ELEMENTS


Une chaîne de caractères est une variable pour un programme: on y accède en l‟appelant par
son nom de variable.
Une chaîne est un tableau de caractères: pour accéder à ses éléments on suit la logique d‟un
tableau.
Exemple:
char A[6] = “Hello”;
-> A[0] contient „H‟, A[1] contient „e‟ … A[5] contient „\0‟.

V.7 Tests logiques


En tenant compte de l'ordre alphabétique des caractères, on peut contrôler le type du caractère
(chiffre, majuscule, minuscule).

Exemples
if (C>='0' && C<='9') printf("Chiffre\n", C); if (C>='A' && C<='Z') printf("Majuscule\n",
C);
if (C>='a' && C<='z') printf("Minuscule\n", C);
Il est facile, de convertir des lettres majuscules dans des minuscules:
if (C>='A' && C<='Z') C = C-'A'+'a';

35
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

ou vice-versa:
if (C>='a' && C<='z') C = C-'a'+'A';

V.8 TABLEAUX DE CHAINES


Une chaîne de caractères est un tableau à 1 dimension de caractères.
On peut également définir des tableaux à plusieurs dimensions qui peuvent contenir des mots:
char JOUR[7][9] = {“lundi”,”mardi”,”mercredi”,”jeudi”,”vendredi”,”samedi”,”dimanche”};
et on peut accéder à ces mots en utilisant la syntaxe suivante:
int I=2;
printf(“Aujourd‟hui nous sommes %s”, JOUR[I]);
qui affichera “Aujourd‟hui nous sommes mercredi”.
Pour accéder à une lettre dans un mot: on écrit JOUR[I][j] avec %c pour l‟affichage.

V.9 FONCTIONS DE BIBLIOTHEQUE


Des fonctions de traitement des chaînes de caractères sont disponibles dans les bibliothèques
standards:
La bibliothèque <stdio.h>:
La bibliothèque <stdio.h> nous offre des fonctions qui effectuent l'entrée et la sortie des
données. A côté des fonctions printf et scanf que nous connaissons déjà, nous y trouvons les
deux fonctions puts et gets, spécialement conçues pour l'écriture et la lecture de chaînes de
caractères.

- Affichage de chaînes de caractères

printf avec le spécificateur de format %s permet d'intégrer une chaîne de caractères dans une
phrase.

En plus, le spécificateur %s permet l'indication de la largeur minimale du champ d'affichage.


Dans ce champ, les données sont justifiées à droite. Si on indique une largeur minimale
négative, la chaîne sera justifiée à gauche. Un nombre suivant un point indique la
largeur maximale pour l'affichage.

Exemples

char NOM[] = "hello, world";


printf(":%s:", NOM); -> :hello, world:

printf(":%5s:", NOM); -> :hello, world:

printf(":%15s:", NOM); -> :hello, world:

printf(":%-15s:", NOM); -> :hello, world :

printf(":%.5s:", NOM); -> :hello:

36
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

puts est idéale pour écrire une chaîne constante ou le contenu d'une variable dans une ligne
isolée.

Syntaxe: puts( <Chaîne> )


puts écrit la chaîne de caractères désignée par <Chaîne> sur stdout et provoque un
Effet:
retour à la ligne. En pratique.

puts(TXT); est équivalent à printf("%s\n",TXT);

Exemples
char TEXTE[] = "Voici une première ligne.";
puts(TEXTE);
puts("Voici une deuxième ligne.");

- Lecture de chaînes de caractères

scanf avec le spécificateur %s permet de lire un mot isolé à l'intérieur d'une suite de données
du même ou d'un autre type.
scanf avec le spécificateur %s lit un mot du fichier d'entrée standard stdin et le
Effet:
mémorise à l'adresse qui est associée à %s.

Exemple
char LIEU[25];
int JOUR, MOIS, ANNEE;
printf("Entrez lieu et date de naissance : \n");
scanf("%s %d %d %d", LIEU, &JOUR, &MOIS, &ANNEE);

Remarques importantes

- La fonction scanf a besoin des adresses de ses arguments:

* Les noms des variables numériques (int, char, long, float, ...) doivent être marqués par le
symbole '&'.

* Comme le nom d'une chaîne de caractères est le représentant de l'adresse du premier


caractère de la chaîne, il ne doit pas être précédé de l'opérateur adresse '&' !

- La fonction scanf avec plusieurs arguments présuppose que l'utilisateur connaisse


exactement le nombre et l'ordre des données à introduire! Ainsi, l'utilisation de scanf pour la
lecture de chaînes de caractères est seulement conseillée si on est forcé de lire un nombre fixé
de mots en une fois.

gets est idéal pour lire une ou plusieurs lignes de texte (p.ex. des phrases) terminées par un
retour à la ligne.
Syntaxe: gets( <Chaîne> )
Effet: gets lit une ligne de de caractères de stdin et la copie à l'adresse indiquée par

37
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

<Chaîne>. Le retour à la ligne final est remplacé par le symbole de fin de


chaîne '\0'.

Exemple

int MAXI = 1000;


char LIGNE[MAXI];
gets(LIGNE);
 Les fonctions de la bibliothèque <string.h>

La bibliothèque <string.h> fournit une multitude de fonctions pratiques pour le


traitement de chaînes de caractères. Voici une brève description des fonctions les plus
fréquemment utilisées.

Dans le tableau suivant, <n> représente un nombre du type int. Les symboles <s> et
<t> peuvent être remplacés par :

* une chaîne de caractères constante

* le nom d'une variable déclarée comme tableau de char

* un pointeur sur char (voir chapitre 9)

- Fonctions pour le traitement de chaînes de caractères

fournit la longueur de la chaîne sans compter le '\0'


strlen(<s>) final

strcpy(<s>, <t>) copie <t> vers <s>

strcat(<s>, <t>) ajoute <t> à la fin de <s>

compare <s> et <t> lexico graphiquement et fournit


strcmp(<s>, <t>)
un résultat:

si <s> précède
négatif
<t>

si <s> est égal à


zéro
<t>

positif si <s> suit <t>

strncpy(<s>, <t>,
copie au plus <n> caractères de <t> vers <s>
<n>)

strncat(<s>, <t>,
ajoute au plus <n> caractères de <t> à la fin de <s>
<n>)

38
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

CHAPITRE VI : LES STRUCTURES ET LES ENUMERATIONS

VI.1 LES STRUCTURES

VI.1.1 Définition : Les structures sont des objets regroupant plusieurs données de types
différents appelées "champs".
Ils sont à définir hors d‟une fonction.
VI.1.2 SYNTAXE
La syntaxe de la déclaration d‟une structure en C est la suivante :
struct nom {
type_champ1 nom_champ1;
type_champ2 nom_champ2;
...
};
La définition d'une structure ne réserve pas d'espace mémoire. Il faut définir les variables
correspondant à ce modèle de structure : struct struct nom_type nom_var ou struct nom_type
*nomptr_var;
Exemple1
struct date {
int j our ;
int mois ;
int annee ;
};
date obdate, *ptdate ;.
L‟accès aux différents champs se fait par : nom_var.nom_champ ou
nomptr_var->nom_champ où la flèche est construite avec le signe moins (-) et le signe
supérieur (>).
VI.1.3 EXEMPLE D’APPLICATION:
#include<stdio.h>
struct complex {
double reel;
double imaginaire;
};
int main()
{
struct complex c;
c.real=1.2;
c.imaginary=6.3;
printf("%f+%f*i\n",c.reel,c.imaginaire);
return 0; }

VI.1.4 DEFINITION DE TYPES COMPOSES AVEC Typedef


Pour alléger l'écriture des programmes, on peut affecter un nouvel identificateur à un type
composé à l'aide de typedef dont la syntaxe est : typedef type synonyme;
Par exemple:
typedef unsigned int UINT; // UINT est synonyme de unsigned int

39
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

int main(void)
{
UINT z; // z sera un unsigned int
}
Il est donc également possible de faire appel à typedef afin de systématiser la syntaxe :
// déclaration d'un type structure
typedef struct nom {
type_champ1 nom_champ1;
type_champ2 nom_champ2;
...
} TypeModele;
// déclaration d'un objet de ce type
TypeModele objet qui est synonyme de la structure définie.
Ainsi, une variable basée sur ce type est déclarée de la sorte : TypeModele nom_var;
Exemple2

#include <math.h>
typedef struct
{
double reelle;
double imaginaire;
} TComplexe;
int main()
{
Tcomplexe z;
double norme;
...
norme = sqrt(z.reelle * z.reelle + z.imaginaire *
z.imaginaire);
printf("norme de (%f + i %f) = %f
\n",z.reelle,z.imaginaire,norme);
return 0;
}

VI.1.5 UTILISATION D’UNE STRUCTURE

Les structures peuvent être manipulées champ par champ ou dans leur ensemble.

VI.1.5.1 OPERATIONS SUR LES CHAMPS

Nous avons dit un peu plus que l'accès aux éléments d'une structure, que nous appelons aussi
champs, se fait selon la syntaxe : nom_de_variable.nom_du_champ.
Lorsqu'on dispose d'un pointeur sur une structure, l'écriture diffère un peu en s'écrivant :
nom_de_variable->nom_du_champ, où la flèche est construite avec le signe moins (-) et le
signe supérieur (>).
En prenant les définitions de données suivantes, le tableau ci-dessous donne les différentes
possibilités d'affectation pour chaque champ.
struct date obdate , *ptdate ;
ptdate = &obdate ;
Une fois ces définitions réalisées, nous pouvons utiliser les variables obdate et ptdate comme
le montre le tableau ci-dessous

40
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Adressage dans une structure.


Objet Pointeur

obdate.jour = 1; ptdate->jour = 1 ;

obdate.mois = 1 ; ptdate->mois = 1 ;

obdate.annee = 85 ; ptdate->annee = 85 ;

Nous remarquerons l'équivalence d'écriture entre : (*ptdate).jour et ptdate->jour.

Pour le compilateur, l'accès à un champ d'une structure revient à faire un calcul de


déplacement par rapport au début de la structure.

VI.1.6 TABLEAUX DANS UNE STRUCTURE


Les structures peuvent contenir des tableaux.
Exemple :
struct Personne
{
char nom[100];
char prenom[100];
char adresse[1000];
long age;
int garcon; // Booléen : 1 = garçon, 0 = fille
};
Cette structure est composée de 5 sous-variables. Les 3 premières sont des chaînes, qui
stockeront le nom, le prénom et l'adresse de la personne.
Les 2 dernières stockent l'âge et le sexe de la personne. Le sexe est un booléen, 1 = vrai =
garçon, 0 = faux = fille.
VI.1.7 INITIALISATION DES STRUCTURES
Les règles d'initialisation d'une structure lors de sa déclaration sont les mêmes que pour les
tableaux. On écrit par exemple :
Tcomplexe z = {2.1 , 2.1};
En ANSI C, on peut appliquer l'opérateur d'affectation aux structures (à la différence des
tableaux). Dans le contexte précédent, on peut écrire :
int main(void)
{
Tcomplexe z1, z2;
z1.r=1;
z1.i=2;...
z2 = z1;
return 0;
}

VI.3 LES ENUMERATIONS


Les énumérations permettent de définir un type par la liste des valeurs qu'il peut prendre. Un
objet de type énumération est défini par le mot-clef enum et un identificateur de modèle,
suivis de la liste des valeurs que peut prendre cet objet
enum modele {constante_1, constante_2,...,constante_n};

41
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

En réalité, les objets de type enum sont représentés comme des int. Les valeurs possibles
constante_1, constante_2,..., constante_n sont codées par des entiers de 0 à n-1. Par
exemple, le type enum booleen défini dans le programme suivant associe l'entier 0 à la valeur
faux et l'entier 1 à la valeur vrai.
int main(void)
{
enum booleen {faux=0, vrai=1};
enum booleen b;
b = vrai;
printf("b = %d\n",b);
return 0;
}
On peut modifier le codage par défaut des valeurs de la liste lors de la déclaration du type
énuméré, par exemple :
enum booleen {faux = 12, vrai = 23};

CHAPITRE VII : LES FICHIERS


VII.1 Introduction et définition.
Le défaut avec les variables, c'est qu'elles n'existent que dans la mémoire vive. Une fois un
programme arrêté, toutes les variables sont supprimées de la mémoire et il n'est pas possible
de retrouver ensuite leur valeur.
Comment, dans ce cas-là, peut-on enregistrer les meilleurs scores obtenus à son jeu?
Comment peut-on faire un éditeur de texte si tout le texte écrit disparaît une fois lorsqu'on
arrête le programme ?
Heureusement, on peut lire et écrire dans des fichiers en langage C.
Les fichiers seront écrits sur le disque dur de l‟ordinateur : l'avantage est donc qu'ils restent là
même si le programme ou l'ordinateur est arrêté.
VII.2 Lire et écrire dans des fichiers
Pour lire et écrire dans des fichiers, nous allons les pointeurs, les structures, les pointeurs de
structures, les chaînes de caractères etc.
2-1. Ouvrir et fermer un fichier
Pour lire et écrire dans des fichiers, nous allons nous servir de fonctions situées dans la
librairie stdio.h savoir printf, scanf et les fonctions faites pour travailler sur les fichiers.
Il faut inclure bien au moins les librairies stdio.h et stdlib.h en haut de votre fichier .c :
#include <stdlib.h>
#include <stdio.h>
Voici ce qu'il faut faire à chaque fois dans l'ordre quand on veut ouvrir un fichier (que ce soit
pour lire ou pour écrire dedans) :
On appelle la fonction d'ouverture de fichier fopen qui nous renvoie un pointeur sur le fichier.
On vérifie si l'ouverture a réussi (c'est-à-dire si le fichier existait) en testant la valeur du
pointeur qu'on a reçu. Si le pointeur vaut NULL, c'est que l'ouverture du fichier n'a pas
marché, il faut afficher un message d'erreur.

42
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Si l'ouverture a marché, alors on peut s'amuser à lire et écrire dans le fichier à travers des
fonctions que nous verrons un peu plus loin.
Il faut penser à fermer le fichier une fois le travail terminé avec la fonction fclose.
a) fopen : ouverture du fichier
Son prototype est le suivant :
FILE* fopen(const char* nomDuFichier, const char* mode Ouverture);

Cette fonction attend 2 paramètres :


Le nom du fichier à ouvrir.
Le mode d'ouverture du fichier, c'est-à-dire une indication qui dit si vous voulez juste écrire
dans le fichier, juste lire dans le fichier, ou les deux à la fois
Cette fonction renvoie un pointeur sur FILE.

Il est extrêmement important de récupérer ce pointeur, pour pouvoir en suite lire et écrire dans
le fichier.
Nous allons donc créer un pointeur de FILE au début de notre fonction (par exemple la
fonction main) :

main()
{FILE* fichier = NULL;
return 0;
}
Le pointeur est initialisé à NULL dès le début. C'est une règle fondamentale que d'initialiser
ses pointeurs à NULL dès le début si on n'a pas d'autre valeur à leur donner. Si cela n‟est pas
fait, vous risquez multiples plantages par la suite.
Maintenant, nous allons appeler la fonction fopen et récupérer la valeur qu'elle renvoie dans
le pointeur "fichier". Mais avant ça, il faut savoir comment se servir du second paramètre, le
paramètre "mode Ouverture". En effet, il y a un code à envoyer qui indiquera à l'ordinateur si
vous ouvrez le fichier en mode de lecture seule, d'écriture seule, ou des deux à la fois.
Voici les modes d'ouvertures possibles :
 "r" : lecture seule. Vous pourrez lire le contenu du fichier, mais pas écrire dedans. Le
fichier doit avoir été créé au préalable.
 "w" : écriture seule. Vous pourrez écrire dans le fichier, mais pas lire son contenu. Si
le fichier n'existe pas, il sera créé.
 "a" : mode d'ajout. Vous écrirez dans le fichier, en partant de la fin du fichier. Vous
rajouterez donc du texte à la fin du fichier.
Si le fichier n'existe pas, il sera créé.
 "r+" : lecture et écriture. Vous pourrez lire et écrire dans le fichier. Le fichier doit
avoir été créé au préalable.
 "w+" : lecture et écriture, avec suppression du contenu au préalable. Le fichier
est donc d'abord vidé de son contenu, et vous écrivez et lisez ensuite dedans. Si le
fichier n'existe pas, il sera créé.
 "a+" : ajout en lecture / écriture à la fin. Vous écrivez et lisez du texte à partir de la
fin du fichier. Si le fichier n'existe pas, il sera créé.
Pour chaque mode qu'on a vu là, si vous rajoutez un "b" après le premier caractère ("rb",
"wb", "ab", "rb+", "wb+", "ab+"), alors le fichier est ouvert en mode binaire. C'est un
mode un peu particulier que nous ne verrons pas ici. En fait, le mode texte est fait pour
stocker du texte comme le nom l'indique (uniquement des caractères affichables), tandis
que le mode binaire permet de stocker... des informations octet par octet (des nombres

43
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

principalement). C'est sensiblement différent. Vous utiliseriez par exemple le mode


binaire pour lire et écrire des fichiers Word octet par octet.
Le fonctionnement est quasiment le même de toute façon que ce que nous allons voir ici.
On a déjà fort à faire avec ces 6 modes d'ouverture à retenir.
On utilise souvent "r" (lecture), "w" (écriture) et "r+" (lecture et écriture). Le mode "w+" est
un peu dangereux parce qu'il vide de suite le contenu du fichier, sans demande de
confirmation. Il ne doit être utilisé que si vous voulez d'abord réinitialiser le fichier.
Le mode d'ajout ("a") peut être utile dans certains cas, si vous voulez juste rajouter des
informations à la fin du fichier.

Le code suivant ouvre le fichier test.txt en mode "r+" (lecture / écriture) :

main()
{
FILE* fichier = NULL;
fichier = fopen("test.txt", "r+");
return 0;
}
Le pointeur "fichier" devient alors un pointeur sur "test.txt" et doit être situé dans le même
dossier que votre exécutable (.exe).
Le fichier doit-il être de type .txt ?
Non. C'est vous qui choisissez l'extension lorsque vous ouvrez le fichier. Vous pouvez très
bien inventer votre propre format de fichier
".niveau" pour enregistrer les niveaux de vos jeux par exemple
Le fichier doit-il être obligatoirement dans le même répertoire que l'exécutable ?
Non plus. Il peut être dans un sous-dossier :
fichier = fopen("dossier/test.txt", "r+");
Ici, le fichier test.txt est dans un sous-dossier appelé "dossier". Cette méthode, que l'on
appelle chemin relatif est plus pratique.
Comme ça, cela fonctionnera peu importe l'endroit où est installé votre programme. C'est
donc plus pratique.
Il est aussi possible d'ouvrir un autre fichier n'importe où ailleurs sur le disque dur. Dans ce
cas, il faut écrire le chemin complet (ce qu'on appelle le chemin absolu) :
fichier = fopen("C:\\Program Files\\Notepad++\\readme.txt", "r+");
Ce code ouvre le fichier readme.txt situé dans "C:\Program Files\Notepad++".
Tester l'ouverture du fichier
Le pointeur "fichier" devrait contenir l'adresse de la structure de type FILE qui sert de
descripteur de fichier. Celui-ci a été chargé en mémoire par la fonction fopen().
A partir de là, 2 possibilités :
- Soit l'ouverture a réussi, et vous pouvez continuer (c'est-à-dire commencer à lire et
écrire dans le fichier).
- Soit l'ouverture a échoué parce que le fichier n'existait pas ou était utilisé par un autre
programme. Dans ce cas, vous devez arrêter de travailler sur le fichier.
Juste après l'ouverture du fichier, il faut absolument vérifier si l'ouverture a réussi ou pas.
Pour faire ça, c'est très simple : si le pointeur vaut NULL, l'ouverture a échoué. S'il vaut autre
chose que NULL, l'ouverture a réussi.
On va donc suivre systématiquement le schéma suivant :
int main()
{
FILE* fichier = NULL;

44
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

fichier = fopen("test.txt", "r+");


if (fichier != NULL)
{
// On peut lire et écrire dans le fichier
}
else
{
// On affiche un message d'erreur si on veut
printf("Impossible d'ouvrir le fichier test.txt");
}
return 0;
}
Faites toujours ça lorsque vous ouvrez un fichier. Si vous ne le faites pas et que le fichier
n'existe pas, vous risquez un plantage du programme ensuite.
b) fclose : fermer le fichier
Si l'ouverture du fichier a réussi, vous pouvez lire et écrire dedans (nous allons voir de suite
après comment faire).
Une fois le travail fini avec le fichier, il faudra le "fermer". On utilise pour cela la fonction
fclose qui a pour rôle de libérer la mémoire, c'est-à-dire supprimer votre fichier chargé dans la
mémoire vive.
Son prototype est :
int fclose(FILE* pointeurSurFichier);
Cette fonction prend un paramètre : votre pointeur sur le fichier.
Elle renvoie un int qui indique si elle a réussi à fermer le fichier. Cet int vaut :
0 : si la fermeture a marché
EOF : si la fermeture a échoué. EOF est un define situé dans stdio.h qui correspond à un
nombre spécial, utilisé pour dire soit qu'il y a eu une erreur, soit qu'on est arrivés à la fin du
fichier. Dans le cas présent cela signifie qu'il y a eu une erreur.
Pour fermer le fichier, on va donc écrire :
fclose(fichier);

Au final, le schéma à suivre pour ouvrir et fermer un fichier sera le suivant :


main()
{
FILE* fichier = NULL;
fichier = fopen("test.txt", "r+");
if (fichier != NULL)
{
// On lit et on écrit dans le fichier
// ...
fclose(fichier); // On ferme le fichier qui a été ouvert
}
return 0;
}
Il faut toujours penser à fermer son fichier une fois que l'on a fini de travailler avec. Cela
permet de libérer de la mémoire.
Si vous oubliez de libérer la mémoire, votre programme risque à la fin de prendre
énormément de mémoire qu'il n'utilise plus.

45
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Votre programme se mettra alors à utiliser plus de mémoire que nécessaire sans que vous
arriviez à comprendre pourquoi. Bien souvent, il s'agit simplement d'un ou deux trucs comme
des petits fclose oubliés.

2-3) Différentes méthodes de lecture/écriture


Maintenant que nous avons écrit le code qui ouvre et ferme le fichier, nous n'avons plus qu'à
insérer le code qui lit et écrit dedans.
Nous allons commencer par voir comment écrire dans un fichier (ce qui est un peu plus
simple), puis nous verrons ensuite comment lire dans un fichier.
a) Ecrire dans le fichier
Il existe plusieurs fonctions capables d'écrire dans un fichier. Ce sera à nous de choisir celle
qui est la plus adaptée à votre cas.
Voici les 3 fonctions que nous allons étudier :
fputc : écrit un caractère dans le fichier (un seul caractère à la fois).
fputs : écrit une chaîne dans le fichier
fprintf : écrit une chaîne "formatée" dans le fichier, fonctionnement quasi-identique à printf.
 fputc
Cette fonction écrit un caractère à la fois dans le fichier. Son prototype est :
int fputc(int caractere, FILE* pointeurSurFichier);
Elle prend 2 paramètres :
Le caractère à écrire (de type int, ce qui comme je vous l'ai dit revient plus ou moins à utiliser
un char, sauf que le nombre de caractères utilisables est ici plus grand). Vous pouvez donc
écrire directement 'A' par exemple.
Le code suivant écrit la lettre 'A' dans test.txt (si le fichier existe, il est remplacé ; si il n'existe
pas, il est créé). Il y a tout dans ce code : ouverture, test de l'ouverture, écriture et fermeture.
main()
{
FILE* fichier = NULL;
fichier = fopen("test.txt", "w");
if (fichier != NULL)
{
fputc('A', fichier); // Ecriture du caractère A
fclose(fichier);
}
return 0;
}
 fputs
Cette fonction est très similaire à fputc, à la différence près qu'elle écrit toute une chaîne, ce
qui est en général plus pratique que d'écrire caractère par caractère
Ceci dit, fputc reste utile lorsque vous devez écrire caractère par caractère, ce qui arrive
fréquemment
Prototype de la fonction :
char* fputs(const char* chaine, FILE* pointeurSurFichier);
Les 2 paramètres sont faciles à comprendre :
chaine : la chaîne à écrire. Notez que le type ici est const char* : en rajoutant le mot const
dans le prototype, la fonction indique que la chaîne sera considérée comme une constante. En
1 mot comme en 100 : elle s'interdit de modifier le contenu de votre chaîne. C'est logique
quand on y pense : fputs doit juste lire votre chaîne, pas la modifier. C'est donc pour vous une
information (et une sécurité) comme quoi votre chaîne ne subira pas de modification

46
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

pointeurSurFichier : comme pour fputc, il s'agit de votre pointeur de type FILE* sur le
fichier que vous avez ouvert.
La fonction renvoie EOF s'il y a eu une erreur, sinon c'est que cela a fonctionné. Là non plus,
je ne teste en général pas la valeur de retour.
Testons l'écriture d'une chaîne dans le fichier :
main()
{
FILE* fichier = NULL;
fichier = fopen("test.txt", "w");
if (fichier != NULL)
{
fputs("Salut les amis\n Comment allez-vous ?", fichier);
fclose(fichier);
}
return 0;
}
 fprintf
Voici un autre exemplaire de la fonction printf. Celle-ci peut être utilisée pour écrire dans un
fichier. Elle s'utilise de la même manière que printf d'ailleurs, excepté le fait que vous devez
indiquer un pointeur de FILE en premier paramètre.
Ce code demande l'âge de l'utilisateur et l'écrit dans le fichier :
main( )
{
FILE* fichier = NULL;
long age = 0;
fichier = fopen("test.txt", "w");
if (fichier != NULL)
{
// On demande l'âge
printf("Quel age avez-vous ? ");
scanf("%ld", &age);
// On l'écrit dans le fichier
fprintf(fichier, "Le Monsieur qui utilise le programme a %ld ans", age);
fclose(fichier);
}
return 0;
}
b) Lire dans un fichier
Nous pouvons utiliser quasiment les mêmes fonctions que pour l'écriture, le nom change juste
un petit peu :
fgetc : lit un caractère
fgets : lit une chaîne
fscanf : lit une chaîne formatée
 fgetc
Tout d'abord le prototype :
int fgetc(FILE* pointeurDeFichier);
Cette fonction retourne un int : c'est le caractère qui a été lu.
Si la fonction n'a pas pu lire de caractère, elle retourne EOF.
Mais comment savoir quel caractère on lit ? Si on veut lire le 3ème caractère, ainsi que le
10ème caractère, comment doit-on faire ?

47
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

En fait, au fur et à mesure que vous lisez un fichier, vous avez un "curseur" qui avance. C'est
un curseur virtuel, on ne le voie pas à l'écran
Mais vous pouvez imaginer que ce curseur est comme la barre clignotante lorsque vous éditez
un fichier sous Bloc-Notes. Il indique où vous en êtes dans la lecture du fichier.
Nous verrons peu après comment savoir à quelle position le curseur est situé dans le fichier, et
aussi comment modifier la position du curseur (pour le remettre au début du fichier par
exemple, ou le placer à un caractère précis, comme le 10ème caractère).
fgetc avance le curseur d'un caractère à chaque fois que vous en lisez un. Si vous appelez
fgetc une seconde fois, la fonction lira donc le second caractère, puis le troisième et ainsi de
suite.
Vous pouvez faire une boucle pour lire les caractères un par un dans le fichier
On va écrire un code qui lit tous les caractères d'un fichier un à un, et qui les écrit à chaque
fois à l'écran.
La boucle s'arrête quand fgetc renvoie EOF (qui signifie End Of File, c'est-à-dire "fin du
fichier").
main()
{
FILE* fichier = NULL;
int caractereActuel = 0;
fichier = fopen("test.txt", "r");
if (fichier != NULL)
{
// Boucle de lecture des caractères un à un
do
{
caractereActuel = fgetc(fichier); // On lit le caractère
printf("%c", caractereActuel); // On l'affiche
} while (caractereActuel != EOF); // On continue tant que fgetc n'a pas retourné EOF
(fin de fichier)
fclose(fichier);
}
return 0;
}
 fgets
Cette fonction lit une chaîne dans le fichier. Ça vous évite d'avoir à lire tous les caractères un
par un. La fonction lit au maximum une ligne (elle s'arrête au premier \n qu'elle rencontre).
Si vous voulez lire plusieurs lignes, il faudra faire une boucle.
Voici le prototype de fgets :
char* fgets(char* chaine, int nombreDeCaracteresALire, FILE* pointeurSurFichier);
Cette fonction demande un paramètre un peu particulier, qui va en fait s'avérer très pratique :
le nombre de caractères à lire. Cela demande à la fonction fgets de s'arrêter de lire la ligne si
elle contient plus de X caractères.
Avantage : ça nous permet de nous assurer que l'on ne fera pas de dépassement de mémoire !
En effet, si la ligne est trop grosse pour rentrer dans chaine, la fonction aurait lu plus de
caractères qu'il n'y a de place, ce qui aurait probablement provoqué un plantage du
programme.
- Lire une ligne avec fgets
Nous allons d'abord voir comment lire une ligne avec fgets (nous verrons ensuite comment
lire tout le fichier).

48
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

On crée une chaîne suffisamment grande pour stocker le contenu de la ligne qu'on va lire (du
moins on espère). Vous allez voir là tout l'intérêt d'utiliser un define pour définir la taille du
tableau :
Code
#define TAILLE_MAX 1000 // Tableau de taille 1000
main()
{
FILE* fichier = NULL;
char chaine [TAILLE_MAX] = ""; // Chaîne vide de taille TAILLE_MAX
fichier = fopen("test.txt", "r");
if (fichier != NULL)
{
fgets(chaine, TAILLE_MAX, fichier); // On lit maximum TAILLE_MAX caractères du
fichier, on stocke le tout dans "chaine"
printf("%s", chaine); // On affiche la chaîne
fclose(fichier);
}
return 0;
}
- Lire tout le fichier avec fgets
Comme nous le savons, fgets lit au maximum toute une ligne à la fois. Elle s'arrête de lire la
ligne si elle dépasse le nombre de caractères maximum que vous autorisez.
Oui mais voilà, pour le moment on ne sait lire qu'une seule ligne à la fois avec fgets.
Comment lire tout le fichier ?
La réponse est simple : avec une boucle
La fonction fgets renvoie NULL si elle n'est pas parvenue à lire ce que vous avez demandé.
La boucle doit donc s'arrêter dès que fgets se met à renvoyer NULL.
On n'a plus qu'à faire un while pour boucler tant que fgets ne renvoit pas NULL.
Code : C

#define TAILLE_MAX 1000


int main()
{
FILE* fichier = NULL;
char chaine[TAILLE_MAX] = "";
fichier = fopen("test.txt", "r");
if (fichier != NULL)
{
while (fgets(chaine, TAILLE_MAX, fichier) != NULL) // On lit le fichier tant qu'on ne reçoit
pas d'erreur (NULL)
{
printf("%s", chaine); // On affiche la chaîne qu'on vient de lire
}
fclose(fichier);
}
return 0;
}

49
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

 fscanf
C'est le même principe que la fonction scanf là encore.
Cette fonction lit dans un fichier qui doit avoir été écrit d'une manière précise.
Supposons que votre fichier contienne 3 nombres séparés par un espace, qui sont par exemple
les 3 plus hauts scores obtenus à votre jeu:
15 20 30
Vous voudriez récupérer chacun de ces nombres dans une variable de type long.
La fonction fscanf va vous permettre de faire ça rapidement.
Code : C
main()
{
FILE* fichier = NULL;
long score[3] = {0}; // Tableau des 3 meilleurs scores
fichier = fopen("test.txt", "w");
if (fichier != NULL)
{
printf("Quels sont les trois scores obtenus\n?");
int i;
for( i=0;i<3;i++)
scanf("%ld",&score[i]);
fscanf(fichier, "%ld %ld %ld", &score[0], &score[1],
&score[2]);
printf("Les meilleurs scores sont : %ld, %ld et %ld",
score[0], score[1], score[2]);
fclose(fichier);
}
else printf("Attention problème fichier non créer\n");
return 0;
}
2-4) Se déplacer dans un fichier
A chaque fois que vous ouvrez un fichier, il existe en effet un curseur qui indique votre
position dans le fichier. Vous pouvez imaginer que c'est exactement comme le curseur de
votre éditeur de texte (tel bloc-notes). Il indique où vous êtes dans le fichier, et donc où vous
allez écrire.
En résumé : le système de curseur vous permet d'aller lire et écrire à une position précise
dans le fichier.
Il existe 3 fonctions à connaître :
ftell : indique à quelle position vous êtes actuellement dans le fichier
fseek : positionne le curseur à un endroit précis
rewind : remet le curseur au début du fichier (c'est équivalent à demander à la fonction fseek
de positionner le curseur au début).
a) ftell : position dans le fichier
Cette fonction est très simple à utiliser. Elle renvoie la position actuelle du curseur sous la
forme d'un long :
long ftell(FILE* pointeurSurFichier);
Le nombre renvoyé indique donc la position du curseur dans le fichier.
b) fseek : se positionner dans le fichier
Le prototype de fseek est le suivant :
Code : C
int fseek(FILE* pointeurSurFichier, long deplacement, int origine);

50
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

La fonction fseek permet de déplacer le "curseur" d'un certain nombre de caractères (indiqué
par deplacement) à partir de la position indiquée par origine.
Le nombre deplacement peut être un nombre positif (pour se déplacer en avant), nul (= 0) ou
négatif (pour se déplacer en arrière).
Quant au nombre origine, vous pouvez mettre comme valeur l'une des 3 constantes
(généralement des defines) listées ci-dessous :
SEEK_SET : indique le début du fichier.
SEEK_CUR : indique la position actuelle du curseur.
SEEK_END : indique la fin du fichier.
Voici quelques exemples pour bien comprendre comment on jongle avec deplacement et
origine
Le code suivant place le curseur 2 caractères après le début :
Code : C
fseek(fichier, 2, SEEK_SET);
Le code suivant place le curseur 4 caractères avant la position courante :
Code : C
fseek(fichier, -4, SEEK_CUR);
(remarquez que deplacment est négatif car on se déplace en arrière)
Le code suivant place le curseur à la fin du fichier :
Code : C
fseek(fichier, 0, SEEK_END);
Si vous écrivez après avoir fait un fseek qui mène à la fin du fichier, cela rajoutera vos
informations à la suite dans le fichier (ça complètera votre fichier).
En revanche, si vous placez le curseur au début et que vous écrivez, cela écrasera le texte qui
se trouvait là. Il n'y a pas de moyen d'"insérer" de texte dans le fichier (à moins de coder soi-
même une fonction qui lit les caractères d'après pour s'en souvenir avant de les écraser !).
c) rewind : retour au début
Cette fonction est équivalente à utiliser fseek pour nous renvoyer à la position 0 dans le
fichier. Si vous avez eu un magnétoscope un jour dans votre vie, c'est le même nom que la
touche qui permet de revenir en arrière.
Le prototype est tout bête :
Code : C
void rewind(FILE* pointeurSurFichier);
L'utilisation est aussi bête que le prototype.
2-5) Renommer et supprimer un fichier
Nous terminerons ce chapitre en douceur par l'étude de 2 fonctions très simples :
rename : renomme un fichier
remove : supprime un fichier
La particularité de ces fonctions est qu'elles ne nécessitent pas de pointeur de fichier pour
fonctionner. Il suffira juste d'indiquer le nom du fichier à renommer / supprimer
a) rename : renommer un fichier
Son prototype est le suivant :
int rename(const char* ancienNom, const char* nouveauNom);
La fonction renvoie 0 si elle a réussi à renommer, sinon elle renvoie autre chose que 0
Exemple :
main()
{
rename("test.txt", "test_renomme.txt");
return 0;
}

51
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

b) remove : supprimer un fichier


Cette fonction supprime un fichier sans demander son reste :
Code : C
int remove(const char* fichierASupprimer);

NB : Faites très attention en utilisant cette fonction ! Elle supprime le fichier indiqué sans
demander de confirmation ! Le fichier n'est pas mis dans la corbeille ni rien, il est
littéralement supprimé du disque dur. Il n'est pas possible de récupérer un fichier supprimé.
Cette fonction tombe à pic pour la fin du chapitre, je n'ai justement plus besoin du fichier
test.txt, je vais donc le supprimer
Code : C
int main(int argc, char *argv[])
{
remove("test.txt");
return 0;
}
CHAPITRE VIII : LE PREPROCESSEUR
Nous avons déjà été amenés à évoquer l'existence d'un "préprocesseur". Il s'agit d'un
programme qui est exécuté automatiquement avant la compilation et qui transforme votre
fichier source à partir d'un certain nombre de "directives". Ces dernières, contrairement à ce
qui se produit pour les instructions du langage C, sont écrites sur des lignes distinctes du reste
du programme ; elles sont toujours introduites par un mot précis commençant par le caractère
#.
Parmi ces directives, nous avons déjà utilisé #include et #define. Nous nous proposons ici
d'étudier les diverses possibilités offertes par le préprocesseur, à savoir :
- l'incorporation de fichiers source (directive #include),
- la définition de symboles et de macros (directive #define),
- la compilation conditionnelle.
VIII.1 - LA DIRECTIVE #INCLUDE
La première (et seule) directive que nous ayons vue pour l'instant est #include.
Cette directive permet d'inclure le contenu d'un fichier dans un autre.
On s'en sert en particulier pour inclure des fichiers .h comme les fichiers .h des librairies
(stdlib.h, stdio.h, string.h, math.h...) et vos propres fichiers .h.
Pour inclure un fichier .h se trouvant dans le dossier où est installé votre IDE, vous devez
utiliser les chevrons < > :
Code : C
#include <stdlib.h>
Pour inclure un fichier .h se trouvant dans le dossier de votre projet, vous devez utiliser les
guillemets :
Code : C
#include "monfichier.h"

VIII.2 - LA DIRECTIVE #DEFINE


Elle offre en fait deux possibilités :
- définition de symboles (c'est sous cette forme que nous l'avons employée jusqu'ici),
- définition de macros.
VIII.2.1 Définition de symboles
Une directive telle que :
#define nbmax 5 demande de "substituer" au symbole nbmax le "texte" 5, et cela chaque fois
que ce symbole apparaîtra dans la suite du fichier source.

52
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

Une directive :
#define entier int placée en début de programme, permettra d'écrire "en français" les
déclarations de variables entières. Ainsi, par exemple, ces instructions :
entier a, b ;
entier * p ;
seront remplacées par :
int a, b ;
int * p ;
Il est possible de demander de faire apparaître dans le texte de substitution un symbole déjà
défini. Par exemple, avec ces directives :
#define nbmax 5
....
#define taille nbmax + 1
Chaque mot taille apparaissant dans la suite du programme sera systématiquement remplacé
par 5+1. Notez bien que taille ne sera pas remplacé exactement par 6 mais, compte tenu de ce
que le compilateur accepte les "expressions constantes" là où les constantes sont autorisées, le
résultat sera comparable (après compilation).
Il est même possible de demander de substituer à un symbole un "texte vide". Par exemple,
avec cette directive :
#define rien
tous les symboles rien figurant dans la suite du programme seront remplacés par un texte
vide. Tout se passera donc comme s'ils ne figuraient pas dans le programme.
Nous verrons qu'une telle possibilité n'est pas aussi fantaisiste qu'il y paraît au premier abord
puisqu'elle pourra intervenir dans la "compilation conditionnelle".
Voici quelques derniers exemples vous montrant comment résumer en un seul mot une
instruction C :
#define bonjour printf("bonjour")
#define affiche printf("resultat %d\n", a)
#define ligne printf("\n")
Notez que nous aurions pu inclure le point-virgule de fin dans le texte de substitution.
D'une manière générale, la syntaxe de cette directive fait que le symbole à remplacer ne peut
contenir d'espace (puisque le premier espace sert de délimiteur entre le symbole à substituer et
le texte de substitution). Le texte de substitution, quant à lui, peut contenir autant d'espaces
que vous le souhaitez puisque c'est la fin de ligne qui termine la directive. Il est même
possible de le prolonger au-delà, en terminant la ligne par \ et en poursuivant sur la ligne
suivante.
Remarque:
a) Si vous introduisez, par mégarde, un signe = dans une directive #define, aucune erreur
ne sera, bien sûr, détectée par le préprocesseur lui-même. Par contre, en général, cela
conduira à une erreur de compilation. Ainsi, par exemple, avec :
#define N = 5 une instruction telle que :
int t[N] ; deviendra, après traitement par le préprocesseur :
int t[= 5] ; laquelle est manifestement erronée. Notez bien, toutefois, que, la plupart du temps,
vous ne connaîtrez pas le texte généré par le préprocesseur et vous serez simplement en
présence d'un diagnostic de compilation concernant apparemment l'instruction int t[N]. Le
diagnostic de l'erreur en sera d'autant plus délicat.
b) Une autre erreur aussi courante que la précédente consiste à terminer (à tort) une
directive #include par un point-virgule. Les considérations précédentes restent
valables dans ce cas.
VIII.3- DEFINITION DE MACROS

53
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

La définition de macros ressemble à la définition de symboles mais elle fait intervenir la


notion de "paramètres".
Par exemple, avec cette directive :
#define carre(a) a*a le préprocesseur remplacera dans la suite tous les textes de la forme
: carre(x) dans lesquels x représente en fait un symbole quelconque par : x*x
Par exemple : carre(z) deviendra z*z ; carre(valeur) deviendra valeur*valeur ;
carre(12) deviendra 12*12.
La macro précédente ne disposait que d'un seul paramètre, mais il est possible d'en faire
intervenir plusieurs en les séparant, classiquement, par des virgules. Par exemple, avec :
#define dif(a,b) a-b
dif(x,z) deviendrait x-z
dif(valeur+9,n) deviendrait valeur+9-n
Là encore, les définitions peuvent s'imbriquer. Ainsi, avec les deux définitions précédentes, le
texte : dif(carre(p),carre(q)) sera, dans un premier temps, remplacé par : dif(p*p,q*q) puis,
dans un second temps, par : p*p-q*q.
Néanmoins, malgré la puissance de cette directive, il ne faut pas oublier que, dans tous les
cas, il ne s'agit que de substitution de texte. Il est souvent nécessaire de prendre quelques
précautions, notamment lorsque le texte de substitution fait intervenir des opérateurs. Par
exemple, avec ces instructions :
#define DOUBLE(x) x + x
.....
DOUBLE(a)/b
DOUBLE(x+2*y)
DOUBLE(x++)
Le texte généré par le préprocesseur sera le suivant :
a + a/b
x+2*y + x+2*y
x++ + x++
Il est possible de mettre plusieurs lignes de code à la fois. Il suffit de mettre un \ avant chaque
nouvelle ligne, comme ceci :
Code : C
#define RACONTER_SA_VIE() printf("Coucou, je m'appelle Delamou\n"); \
printf("J'habite à Labé\n"); \
printf("J'aime la glace\n");
int main()
{
RACONTER_SA_VIE()
return 0;
}
VIII.4 - LA COMPILATION CONDITIONNELLE
Un certain nombre de directives permettent d'incorporer ou d'exclure des portions du fichier
source dans le texte qui est analysé par le préprocesseur. Ces directives se classent en deux
catégories en fonction de la condition qui régit l'incorporation :
- existence ou inexistence de symboles,
- valeur d'une expression.
VIII.4.1 Incorporation liée à l'existence de symboles
#ifdef symbole
.....
#else
.....

54
Support de cours de C Elaboré par M. Koliko Delamou C.U Labé

#endif
demande d'incorporer le texte figurant entre les deux lignes #ifdef et #else si le symbole
indiqué est effectivement défini au moment où l'on rencontre #ifdef. Dans le cas contraire,
c'est le texte figurant entre #else et #endif qui sera incorporé. La directive #else peut,
naturellement, être absente.
De façon comparable :
#ifndef symbole
.....
#else
.....
#endif
demande d'incorporer le texte figurant entre les deux lignes #ifndef et #else si le symbole
indiqué n'est pas défini. Dans le cas contraire, c'est le texte figurant entre #else et #endif qui
sera incorporé.
Notez bien que, pour qu'un tel symbole soit effectivement défini pour le préprocesseur, il doit
faire l'objet d'une directive #define.
Voici un exemple d'utilisation de ces directives :
#define MISEAUPOINT
.....
#ifdef MISEAUPOINT
instructions 1
#else
instructions 2
#endif
Ici, les instructions 1 seront incorporées par le préprocesseur, tandis que les instructions 2 ne
le seront pas. En revanche, il suffirait de supprimer la directive #define MISEAUPOINT pour
aboutir au résultat contraire.

FIN DU PROGRAMME

55

Vous aimerez peut-être aussi