Vous êtes sur la page 1sur 135

Programmation I

Responsable : Pr. Ayoub Ellahyani


Email: ayoub.ellahyani@yahoo.com
Plan de Cours
• Introduction
• Types de base, variables, constantes
• Opérateurs et expressions
• Les entrées sorties en C
• Les structures de contrôle
• Les tableaux
• Les pointeurs
Chapitre I

Introduction
Introduction
• Généralités sur le langage C (Historique)

• C est un langage de programmation impératif généraliste, de bas niveau. 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.
• Il fut limité à l’usage interne de Bell jusqu’en 1978, date à laquelle Brian Kernighan et Denis Ritchie publièrent les
spécifications définitives du langage : The C programming Language.
• Mais ce 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 Standards Organization), plus récemment en 1993 par le CEN (Comité européen de normalisation) et enfin,
en 1994, par l’AFNOR. 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 ».

• L’ISO a publié en 1999, sous la référence ISO/IEC 9899:1999, une extension de la norme du langage C, plus connue sous
l’acronyme C99. Bien qu’ancienne, celle-ci est loin d’être implémentée dans sa totalité par tous les compilateurs.
Introduction
• Généralités sur le langage C (Intérêt)

• Polyvalent : Il permet le développement de systèmes d’exploitation, de programmes scientifiques et de programmes de


gestion.
• Langage structuré et évolué qui permet néanmoins d’effectuer des opérations de bas niveau (assembleur d’Unix).
• Prés de la machine
• Indépendant de la machine
• Portabilité (en respectant la norme !) :
Recompilation des sources sur la nouvelle plate-forme.
• Compact
• Rapide
code très proche du langage machine.
• Extensible
nombreuses bibliothèques
• Père syntaxique du C++, Java, PHP etc.
Introduction
• Généralités sur le langage C (Inconvénients)

• Trop permissif
Programmation spaghetti et autres …
Warning interdit
• Programme difficile à maintenir si
La programmation est trop compacte
Les commentaires sont insuffisants
• Portabilité
Dès que l’on utilise des bibliothèques externes, la portabilité devient difficile.
Introduction
• Exemple de programme en langage C
Introduction
• Structure d'un programme en langage C
Introduction
• Structure d'un programme en langage C

• La ligne :
main()
se nomme un « en-tête ». Elle précise que ce qui sera décrit à sa suite est en fait le programme principal (main). Le
programme (principal) proprement dit vient à la suite de cet en-tête. Il est délimité par les accolades «{»et «}». On dit que les
instructions situées entre ces accolades forment un « bloc ».
• Les trois instructions :
int i ;
float x ;
float racx ;
sont des « déclarations ». La première précise que la variable nommée i est de type int , c’est-à-dire qu’elle est destinée à
contenir des nombres entiers (relatifs). Les deux autres déclarations précisent que les variables x et racx sont de type float,
c’est à dire qu’elles sont destinées à contenir des nombres flottants (approximation de nombres réels).

Remarque: en C, comme dans la plupart des langages actuels, les déclarations des types des variables sont obligatoires et
doivent être regroupées au début du programme (on devrait plutôt dire: au début de la fonction main). Cependant, suivant
la norme C99, une déclaration peut figurer à n’importe quel emplacement, pour peu qu’elle apparaisse avant que la variable
correspondante ne soit utilisée.
Introduction
• Structure d'un programme en langage C

• L’instruction :
printf ("Bonjour\n") ;
appelle en fait une fonction prédéfinie (fournie avec le langage, et donc que vous n’avez pas à écrire vous-même) nommée
printf. Ici, cette fonction reçoit un argument qui est : « Bonjour\n » Les guillemets servent à délimiter une « chaîne de
caractères » (suite de caractères). La notation \n est conventionnelle : elle représente un caractère de fin de ligne

• L’instruction suivante :
printf ("Je vais vous calculer %d racines carrées\n", NFOIS) ;
ressemble à la précédente avec cette différence qu’ici la fonction printf reçoit deux arguments.
Ici, on demande à printf d’afficher suivant ce format :
"Je vais vous calculer %d racines carrées\n" la valeur de NFOIS , c’est-à-dire, la valeur 5. Ce format est, comme
précédemment, une chaîne de caractères. Toutefois, vous constatez la présence d’un caractère %. Celui-ci signifie que le
caractère suivant est, non plus du texte à afficher tel quel, mais un « code de format ». Ce dernier précise qu’il faut
considérer la valeur reçue (en argument suivant, donc ici 5) comme un entier et l’afficher en décimal.
Introduction
• Structure d'un programme en langage C

• L’instruction :
for (i=0 ; i<NFOIS ; i++)
Son rôle est de répéter le bloc (délimité par des accolades «{» et «}») figurant à sa suite, en respectant les consignes
suivantes:
• avant de commencer cette répétition, réaliser : i = 0
• avant chaque nouvelle exécution du bloc (tour de boucle), examiner la condition : i < NFOIS si elle est satisfaite, exécuter
le bloc indiqué entre les accolades «{» et «}»), sinon passer à l’instruction qui se trouve après le bloc for (i.e. après
l’accolade } ).
• à la fin de chaque exécution du bloc, réaliser : i++ : il s’agit là d’une notation propre au langage C qui est équivalente à : i =
i+1
En définitive, vous voyez qu’ici notre bloc sera répété cinq fois.
Introduction
• Structure d'un programme en langage C

• La première instruction du bloc répété par l’instruction for affiche simplement le message Donnez un nombre:.
Notez qu’ici nous n’avons pas prévu de changement de ligne à la fin.
• La seconde instruction du bloc :
scanf ("%f", &x) ;
est un appel de la fonction prédéfinie scanf dont le rôle est de lire une information au clavier. Comme printf, la fonction scanf
possède en premier argument un format exprimé sous forme d’une chaîne de caractères, ici : "%f" ce qui correspond à une
valeur flottante.
les arguments suivants (ici, il n’y en a qu’un &x) précisent dans quelles variables on souhaite placer les valeurs lues.
Introduction
• Structure d'un programme en langage C

• Les lignes :
if (x < 0.0)
printf ("Le nombre %f ne possède pas de racine carrée\n", x) ;
else{
racx = sqrt (x) ;
printf ("Le nombre %f a pour racine carrée : %f\n", x, racx) ;
}
constituent une instruction de choix basée sur la condition x < 0.0. Si cette condition est vraie, on exécute l’instruction
suivante, c’est-à-dire : printf ("Le nombre %f ne possède pas de racine carrée\n", x) ; Si elle est
fausse, on exécute l’instruction suivant le mot else, c’est-à-dire, ici, le bloc :
{ racx = sqrt (x) ;
printf ("Le nombre %f a pour racine carrée : %f\n", x, racx) ;
}
La fonction sqrt fournit la valeur de la racine carrée d’une valeur flottante qu’on lui transmet en argument.
Introduction
• Structure d'un programme en langage C

• Les trois premières lignes de notre programme :


#include <stdio.h>
#include <math.h>
#define NFOIS 5
sont en fait un peu particulières. Il s’agit de directives qui seront prises en compte avant la traduction
(compilation) du programme. Les deux premières directives demandent en fait d’introduire (avant compilation)
des instructions (en langage C) situées dans les fichiers stdio.h et math.h. Pour l’instant, notez que, dès lors que
vous faites appel à une fonction prédéfinie, il est nécessaire d’incorporer de tels fichiers, nommés « fichiers en-
têtes », qui contiennent des déclarations appropriées concernant cette fonction : stdio.h pour printf et scanf,
math.h pour sqrt. La troisième directive demande simplement de remplacer systématiquement, dans toute la
suite du programme, le symbole NFOIS par 5.
Introduction
• Un second exemple de programme en langage C
Voici un second exemple de programme destiné à vous montrer l’utilisation du type « caractère ». Il demande à l’utilisateur
de choisir une opération parmi l’addition ou la multiplication, puis de fournir deux nombres entiers ; il affiche alors le résultat
correspondant.
Introduction
• Quelques règles d'écriture
Les identificateurs
Les identificateurs servent à désigner les différents « objets » manipulés par le programme : variables,
fonctions, constantes, étiquettes de structure, d'union ou d'énumération, membres de structure ou d'union,
types, macros, 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. 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.

• le caractère souligné (_) est considéré comme une lettre. Il peut donc apparaître au 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. Ainsi, en C, les
identificateurs ligne et Ligne désignent deux objets différents.
Introduction
• Quelques règles d'écriture
Les identificateurs
Voici la liste, classée par ordre alphabétique des « mots-clés » réservés par le langage.
Introduction
• Quelques règles d'écriture
Les identificateurs
Lesquels des identificateurs suivants sont acceptés ?

• fonction-1 • _MOYENNE_du_MOIS_ • 3e_jour • Entier • INT


• limite_inf. • lim_supérieure • __A_ • float • fin

• _ • a • for • Fin_A • 3
Introduction
• Quelques règles d'écriture
Les séparateurs
Dans un programme, deux identificateurs successifs entre lesquels la syntaxe n'impose aucun signe particulier
(tel que :,=;*() [ ] { ) ) doivent impérativement être séparés soit par un espace, soit par une fin de ligne. En
revanche, dès que la syntaxe impose un séparateur quelconque, il n'est alors pas nécessaire de prévoir
d'espaces supplémentaires (bien qu'en pratique cela améliore la lisibilité du programme).

Ainsi, vous devrez impérativement écrire :


int x,y
et non :
intx,y
En revanche, vous pourrez écrire indifféremment :
int n,compte,total,p
ou plus lisiblement :
int n, compte, total, p
Introduction
• Quelques règles d'écriture
Le format libre
Le langage C autorise une mise en page parfaitement libre. En particulier, une instruction peut s'étendre sur un
nombre quelconque de lignes, et une même ligne peut comporter autant d'instructions que vous le souhaitez.

À titre d'exemple, voyez comment pourrait être (mal) présenté notre programme précédent :
Introduction
• Quelques règles d'écriture
Les commentaires
Comme tout langage évolué, le langage C autorise la présence de commentaires dans vos programmes source.
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é. En général, cependant, on se limitera à des emplacements
propices à une bonne lisibilité du programme.
Voici quelques exemples de commentaires :
/* programme de calcul de racines carrées */
/* commentaire fantaisiste &ç§{<>} ?%!!!!!! */
/* commentaire s'étendant sur plusieurs lignes
de programme source */
/* ============================================
* commentaire quelque peu esthétique *
* et encadré, pouvant servir, *
* par exemple, d'en-tête de programme *
============================================ */
Introduction
• Création d'un programme en langage C
L'édition du programme
L'édition du programme (on dit aussi parfois « saisie ») consiste à créer, à partir d'un clavier, tout ou partie du
texte d'un programme qu'on nomme « programme source ». En général, ce texte sera conservé dans un fichier
que l'on nommera « fichier source ». Chaque système possède ses propres conventions de dénomination des
fichiers. En général, un fichier peut, en plus de son nom, être caractérisé par un groupe de caractères (au
moins 3) qu'on appelle une « extension » (ou, parfois un « type ») ; la plupart du temps, en langage C, les
fichiers source porteront l'extension C.
Introduction
• Création d'un programme en langage C
La compilation
Elle consiste à traduire le programme source (ou le contenu d'un fichier source) en langage machine, en faisant
appel à un programme nommé compilateur. En langage C, compte tenu de l'existence d'un préprocesseur, cette
opération de compilation comporte en fait deux étapes :
• traitement par le préprocesseur : ce dernier exécute simplement les directives qui le concernent (il les
reconnaît au fait qu'elles commencent par un caractère #). Il produit, en résultat, un programme source en
langage C pur.
• compilation proprement dite, c'est-à-dire traduction en langage machine du texte en langage C fourni par
le préprocesseur.
Introduction
• Création d'un programme en langage C
L'édition de liens
• Le module objet créé par le compilateur n'est pas directement exécutable. Il lui manque, au moins, les
différents modules objet correspondant aux fonctions prédéfinies (on dit aussi « fonctions standard »)
utilisées par votre programme (comme printf, scanf, sqrt).

• C'est effectivement le rôle de l'éditeur de liens que d'aller rechercher dans la bibliothèque standard les
modules objet nécessaires.

• Le résultat de l'édition de liens est ce que l'on nomme un programme exécutable, c'est-à-dire un ensemble
autonome d'instructions en langage machine.
Introduction
• Création d'un programme en langage C
Outils
Maintenant que les présentations sont faites, il est temps de découvrir les outils nécessaires pour programmer
en C. Le strict minimum pour programmer se résume en trois points.

• Un éditeur de texte : ce logiciel va servir à écrire le code source. En théorie, n’importe quel éditeur de texte
suffit, mais le mieux est d’en avoir un qui colore le code source, ce qui permet une relecture plus agréable.

• Un compilateur : c’est le logiciel le plus important puisqu’il va nous permettre de transformer le code que
l’on écrit en un fichier exécutable compréhensible par le processeur.

• Un débugger / débogueur : fondamentalement, il n’est pas indispensable, mais ce logiciel est très utile pour
chasser les bugs et vérifier le comportement de son programme.
Introduction
• Création d'un programme en langage C
Outils
À partir de là, il existe deux moyens de récupérer tous ces logiciels : soit on les prend séparément, et dans ce cas il faut
compiler par soi-même, soit on utilise un logiciel qui réunit les trois : un IDE (« Environnement de Développement Intégré »
en français).

Exemples des IDEs


• Code::Blocks est un IDE gratuit et libre, qui fonctionne avec plusieurs compilateurs différents et qui n’est pas très
compliqué à prendre en main.
• Visual C++ est un IDE édité par Microsoft et très efficace, car adapté pour Windows. Il possède aussi un débogueur
puissant. Bien qu’il ne soit pas libre, Visual C++ est gratuit (dans sa version express)

Compilateurs
• GNU Compiler Collection, abrégé en GCC, est un ensemble de compilateurs libre capable de compiler divers langages de
programmation, dont C, C++, Objective-C, Java, …
• Borland C++ Compiler est une version gratuite du compilateur C & C++ inclus dans C++ Builder.
• MinGW ou Mingw32 (Minimalist GNU for Windows) est une adaptation des logiciels de développement et de compilation
du GNU (GCC - GNU Compiler Collection), à la plate-forme Win32.
Introduction
• Création d'un programme en langage C
Remarques
Il existe deux types de programmes:
• les programmes avec fenêtres ;
• les programmes en console.

Il existe deux types de configuration:


• "Debug" configuration : pour avoir un exécutable compilé en mode Debug, c’est-à-dire un programme non optimisé qui
contiendra toutes les informations nécessaires pour déboguer. L’exécutable ne sera pas portable.
• "Release" configuration : le programme est optimisé, portable et allégé puisqu’il ne possède plus les informations de
débogage.
Chapitre II

Types de base
Types de base
• La notion de type
Remarque

Les types char, int et float que nous avons déjà rencontrés sont souvent dits scalaires ou simples, car, à un
instant donné, une variable d'un tel type contient une seule valeur. Ils s'opposent aux types structurés qui
correspondent à des variables qui, à un instant donné, contiennent plusieurs valeurs (de même type ou non)
comme les tableaux, les structures, les unions etc.

Dans ce chapitre , nous étudierons en détail ce que l'on appelle les types de base du langage C ; il s'agit des
types scalaires à partir desquels pourront être construits tous les autres types.
Types de base
• La notion de type
La mémoire centrale est un ensemble de positions binaires nommées bits. Ils sont regroupés en octets (8 bits),
et chaque octet est repéré par ce qu'on nomme son adresse. L'ordinateur ne sait représenter et traiter que des
informations exprimées sous forme binaire. Toute information, quelle que soit sa nature, devra être codée sous
cette forme. Dans ces conditions, on voit qu'il ne suffit pas de connaître le contenu d'un emplacement de la
mémoire (d'un ou de plusieurs octets) pour être en mesure de lui attribuer une signification.

Par exemple, si vous savez qu'un octet contient le « motif binaire » suivant : 01001101

• Cela peut représenter le nombre entier 77 (puisque il correspond à la représentation en base 2 de ce


nombre)
• Cela peut représenter le caractère M, (Si le code ASCII est la convention employée sur la machine concernée
pour représenter les caractères)
• Cela peut représenter une partie d'une instruction machine ou d'un nombre entier codé sur deux octets, ou
d'un nombre réel codé sur 4 octets, ou...
Types de base
• La notion de type
Il n'est pas possible d'attribuer une signification à une information binaire tant que l'on ne connaît pas la
manière dont elle a été codée. En général, il ne sera même pas possible de « traiter » cette information.

D'une manière générale, la notion de type, telle qu'elle existe dans les langages évolués, sert à régler (entre
autres choses) les problèmes que nous venons d'évoquer.

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 :
• nombres entiers (mot-clé int),
• nombres flottants (mot-clé float ou double),
• caractères (mot-clé char) ; nous verrons qu'en fait char apparaît (en C) comme un cas particulier de int.
Types de base
• Les types entiers
• Le mot-clé int correspond à la représentation de nombres entiers relatifs. Pour ce faire : un bit est réservé
pour représenter le signe du nombre, les autres bits servent à représenter la valeur absolue du nombre (en
toute rigueur, on la représente sous la forme de ce que l'on nomme le « complément à deux ».

• Chaque type entier a une forme « signée » pouvant représenter des nombres négatifs et positifs, et une
forme « non signée » ne pouvant représenter que des nombre naturels. Les formes signées et non signées
doivent avoir la même taille.

• Contrairement à de nombreux autres langages, le type char est un type entier comme un autre, bien qu'il
soit généralement utilisé pour représenter les caractères. Sa taille est par définition d'un byte.
Types de base
• Les types entiers
• Le C prévoit que, sur une machine donnée, on puisse trouver jusqu'à trois tailles différentes d'entiers,
désignées par les mots-clés suivants:
 short int (qu'on peut abréger en short),
 int (c'est celui que nous avons rencontré dans le chapitre précédent),
 long int (qu'on peut abréger en long).

• Chaque taille impose naturellement ses limites. Toutefois, ces dernières dépendent, non seulement du mot-
clé considéré, mais également de la machine utilisée.

• Chacun des trois types (short, int et long) peut être nuancé par l'utilisation du qualificatif unsigned (non
signé). (Dans ce cas, il n'y a plus de bit réservé au signe et on ne représente plus que des nombres positifs).

• La norme C99 introduit le type long long, ainsi que des types permettant de choisir :
 soit la taille correspondante, par exemple int16 pour des entiers codés sur 16 bits ou int32 pour des
entiers codés sur 32 bits ;
 soit une taille minimale, par exemple int_least32_t pour un entier d'au moins 32 bits.
Types de base
• Les types entiers
Types de base
• Les types flottants
• Les types flottants permettent de représenter, de manière approchée, une partie des nombres réels. Plus
précisément, un nombre réel sera représenté en flottant en déterminant deux quantités M (mantisse) et E
(exposant) telles que la valeur 𝑀. 𝐵𝐸 représente une approximation de ce nombre.
• Le C prévoit trois types de flottants correspondant à des tailles différentes : float, double et long double.
• Comme dans la plupart des langages, les constantes flottantes peuvent s'écrire indifféremment suivant l'une
des deux notations :
• Décimale

• Exponentielle

• La notation exponentielle utilise la lettre e (ou E) pour introduire un exposant entier (puissance de 10), avec
ou sans signe. La mantisse peut être n'importe quel nombre décimal ou entier (le point peut être absent
dès que l'on utilise un exposant).
Types de base
• Les types caractères
• Contrairement à de nombreux autres langages, le type char est un type entier comme un autre, bien qu'il
soit généralement utilisé pour représenter les caractères. Sa taille est par définition d'un byte.

• la notion de caractère en C dépasse celle de caractère imprimable, c'est-à-dire auquel est obligatoirement
associé un graphisme (et qu'on peut donc imprimer ou afficher sur un écran). C'est ainsi qu'il existe certains
caractères de changement de ligne, de tabulation, d'activation d'une alarme sonore (cloche),... Nous avons
d'ailleurs déjà utilisé le premier (sous la forme \n). C’est ce qu’on appel « caractères de contrôle ».

• Les constantes de type « caractère », lorsqu'elles correspondent à des caractères imprimables, se notent de
façon classique, en écrivant entre apostrophes (ou quotes) le caractère voulu, comme dans ces exemples :
Types de base
• Les types caractères
Certains caractères non imprimables possèdent une représentation conventionnelle utilisant le caractère « \ ».
Voici la liste de ces caractères.
Types de base
• Initialisation et constantes
• La directive #define permettait de donner une valeur à un symbole. Dans ce cas, le préprocesseur
effectue le remplacement correspondant avant la compilation.

• Il est possible d'initialiser une variable lors de sa déclaration comme dans :


int n = 15 ;

• Il est possible de déclarer que la valeur d'une variable ne doit pas changer lors de l'exécution du
programme. Par exemple, avec :
const int n = 20 ;
Types de base
• Autres types introduits par la norme C99
Outre les nouveaux types entiers dont nous avons parlé, la norme C99 introduit :

• Le type booléen, sous le nom bool ; une variable de ce type ne peut prendre que l'une des deux valeurs ;
vrai (noté true) et faux (noté false) ;
• Des types complexes, sous les noms float complex, double complex et long double
complex ; la constante I correspond alors à la constante mathématique i (racine de -1).
Chapitre III

Les opérateurs et les


expressions
Les opérateurs et les expressions
• Notions d'opérateur et d'expression en langage C
Les expressions en langage C peuvent être constituées de variables, constantes, éléments de tableau et
références à des fonctions combinés entre eux à l’aide d’opérateurs.
On distingue différentes catégories d’opérateurs:

 Les opérateurs arithmétiques


 Les opérateurs relationnels et logiques
 Les opérateurs d’affectation
 Les opérateurs d’incrémentation et décrémentation
 Les opérateurs d’affectation élargie
 L'opérateur Cast
 L’opérateur conditionnel
 L’opérateur séquentiel
 L'opérateur sizeof
Les opérateurs et les expressions
• Notions d'opérateur et d'expression en langage C
De façon générale, une expression est une combinaison d’opérateurs et d’opérandes dont le résultat est une
valeur.
L’expression possède une valeur mais peut réaliser une affectation à une variable. Car les opérateurs
d’affectation et d’incrémentation peuvent non seulement intervenir dans une expression (qui aura une valeur)
mais agir sur le contenu des variables.

Exemple:

• ++i est une expression qui réalise une action: incrémenter la valeur de i. Elle aura comme valeur, la valeur
de i après incrémentation.
• i = 7 est une expression de valeur 7 qui réalise une action : affecter à i la valeur 7.
• k = (i = 7) La valeur de l’expression ( i = 7) est affectée á la valeur de k.
Les opérateurs et les expressions
• Les opérateurs arithmétiques en C
Opérateurs arithmétiques binaires
+
addition
-
soustraction
/
division
*
multiplication
%
reste de la division entière (modulo)

• Les opérateurs binaires ne sont définis que sur deux opérandes ayant le même type : ( int, long int, float,
double, long double ). Ils fournissent le même type que leurs opérandes.
• L` opérateur modulo ( % ) ne peut porter que sur des entiers.
Les opérateurs et les expressions
• Les opérateurs arithmétiques en C
Opérateur arithmétique unaire
Un opérateur « unaire » (c'est-à-dire ne portant que sur un seul opérande) correspond à l'opposé noté -
(comme dans -n ou dans -x+y).

Exemples :
Étant données a et b des variables de type entier de valeurs respectives 10 et 3, v1 et v2 deux variables de type flottant et
dont les valeurs respectives sont 12.5 et 2.0, et c1 et c2 de type caractère représentant respectivement les caractères ‘P’ et
‘T’.

Expression sa valeur Expression sa valeur Expression sa valeur


a+b 13 v1 + v2 14.5 c1 80 ( code ASCII de P)
a–b 7 v1 – v2 10.5 c2 84 ( code ASCII de T)
a*b 30 v1 * v2 25.0 c1 + c2 164
a /b 3 v1 / v2 6.25 c1 + c2 + 5 169
a%b 1 c1 + c2 + `5` 215
Le code ASCII du caractère `5` est 53.
Les opérateurs et les expressions
• Les opérateurs arithmétiques en C
Les priorités relatives des opérateurs
• Lorsque plusieurs opérateurs apparaissent dans une même expression, il est nécessaire de savoir dans quel ordre ils sont
mis en jeu. Les opérateurs unaires + et - ont la priorité la plus élevée. On trouve ensuite, à un même niveau, les
opérateurs *, / et %. Enfin, sur un dernier niveau, apparaissent les opérateurs binaires + et - .
• En cas de priorités identiques, les calculs s'effectuent de gauche à droite. On dit que l'on a affaire à une associativité de
gauche à droite (nous verrons que quelques opérateurs, autres qu'arithmétiques, utilisent une associativité de droite à
gauche).
• Enfin, des parenthèses permettent d'outrepasser ces règles de priorité, en forçant le calcul préalable de l'expression
qu'elles contiennent. Notez que ces parenthèses peuvent également être employées pour assurer une meilleure lisibilité
d'une expression.
Exemples
Les opérateurs et les expressions
• Les conversions implicites

Une expression mixte est une expression, dans laquelle interviennent des opérandes de types différents.

Dans une expression mixte, le compilateur met en place des instructions de conversion de la valeur d’un
opérande pour obtenir une expression dont tous les opérandes ont le même type. Le résultat de la conversion
sera exprimé dans le type de plus haute précision.

On distingue deux types de conversion :


• Les conversions d'ajustement de type
• Les promotions numériques
Les opérateurs et les expressions
• Les conversions implicites
Les conversions d'ajustement de type
Une conversion telle que int -> float se nomme une « conversion d'ajustement de type ». Une telle conversion ne
peut se faire que suivant une hiérarchie qui permet de ne pas dénaturer la valeur initiale, à savoir :

On peut convertir directement un int en double ; en revanche, on ne pourra pas convertir un double en float ou en int. Par
exemple, si n est de type int, p de type long et x de type float, l'expression :
n * p + x
sera évaluée suivant ce schéma :
Les opérateurs et les expressions
• Les conversions implicites
Les promotions numériques
Les opérateurs arithmétiques ne sont pas définis pour le type short et char. Le langage C prévoit que toute valeur de l’un de
ces types apparaissant dans une expression, est d’abord convertie en int. On parle alors de promotion numérique.
Par exemple, si pl, p2 et p3 sont de type short et x de type float, l'expression :
pl * p2 + p3 * x
est évaluée comme l'indique le schéma ci-après :
Les opérateurs et les expressions
• Les conversions implicites
Les promotions numériques
La promotion numérique permet de considérer le code du caractère ( sur 8 bits) comme la valeur de ce caractère.
Dans ce cas, le langage C confond un caractère avec la valeur ( entier) du code qui le représente.

Remarque :
La valeur entière associée à un caractère donné n’est pas le même sur toutes les machines.

Voici quelques exemples d'évaluation d'expressions, dans lesquels on suppose que cl et c2 sont de type char.
Les opérateurs et les expressions
• Les opérateurs relationnels
• Le langage C permet de comparer des expressions à l’aide d’opérateurs de comparaison.
• Le résultat de la comparaison est une valeur entière de valeur 1 ( si le résultat est vrai) ou 0 ( si le résultat est faux).
• Cette expression faisant intervenir des opérateurs de comparaison, sera alors de type entier et donc pourra intervenir
dans des calculs arithmétiques.

Exemple :
2 * a > b + 5

Remarque :
C se distingue de la plupart des autres langages sur deux points :
• le résultat de la comparaison est, non pas une valeur booléenne (on dit aussi logique) prenant l'une des deux valeurs vrai
ou faux, mais un entier. Ainsi, la comparaison ci-dessus devient en fait une expression de type entier. Cela signifie qu'elle
pourra éventuellement intervenir dans des calculs arithmétiques.
• les expressions comparées pourront être d'un type de base quelconque et elles seront soumises aux règles de conversion
présentées dans le paragraphe précédent. Cela signifie qu'au bout du compte on ne sera amené à comparer que des
expressions de type numérique.
Les opérateurs et les expressions
• Les opérateurs relationnels
Voici la liste des opérateurs relationnels existant en C.

En ce qui concerne leurs priorités, il faut savoir que les quatre premiers opérateurs (<, <=, >, >=) sont de même priorité. Les
deux derniers (== et ! =) possèdent également la même priorité, mais celle-ci est inférieure à celle des précédents. Ainsi,
l'expression :
a < b == c < d
est interprétée comme :
( a < b) == (c < d)
Les opérateurs et les expressions
• Les opérateurs relationnels
• Les opérateurs relationnels sont moins prioritaires que les opérateurs arithmétiques.
Ainsi :
x + y < a + 2
est équivalent à :
( x + y ) < ( a + 2 )

une comparaison peut porter sur deux caractères. Bien entendu, la comparaison d'égalité ne pose pas de
problème particulier ; par exemple (c1 et c2 étant de type char) :
• c1== c2 sera vraie si c1 et c2 ont la même valeur, c'est-à-dire si c1 et c2 contiennent des caractères de
même code, donc si c1 et c2 contiennent le même caractère.
• c1 < c2 sera vraie si le code du caractère de c1 a une valeur inférieure au code du caractère de c2. Le
résultat d'une telle comparaison peut donc varier suivant le codage employé.
Les opérateurs et les expressions
• Les opérateurs logiques
C dispose de trois opérateurs logiques classiques : et (noté &&), ou (noté | | ) et non (noté ! ). Il est important
de constater que, ne disposant pas de type logique, C se contente de représenter vrai par 1 et faux par 0. C'est
pourquoi ces opérateurs produisent un résultat numérique (de type int).
Les opérateurs et les expressions
• Les opérateurs logiques
• L'opérateur ! a une priorité supérieure à celle de tous les opérateurs arithmétiques binaires et aux opérateurs
relationnels.
• L'opérateur || est moins prioritaire que &&. Tous deux sont de priorité inférieure aux opérateurs arithmétiques ou
relationnels.
• Enfin, les deux opérateurs && et || jouissent en C d'une propriété intéressante : leur second opérande (celui qui figure à
droite de l'opérateur) n'est évalué que si la connaissance de sa valeur est indispensable pour décider si l'expression
correspondante est vraie ou fausse.

Exemple :
int i = 7;
float f = 5.5;
char c = ‘w’;

Expression valeur
( i >= 6 ) && ( c = ‘w’ ) 1
( i >= 6 ) || ( c = = 119 ) 1
(f < 11 ) && ( i > 100 ) 0
( c != ‘p’ ) || ( i + f <= 10 ) 1
Les opérateurs et les expressions
• L'opérateur d'affectation
• L'opérateur d’affectation permet de former des expressions d’affectation .
• La partie gauche de l’opérateur d’affectation `` = `` doit être une lvalue (left value). lvalue est une
expression à laquelle on peut affecter une valeur (Les variables sont des lvalues).
• La partie à droite de l’opérateur est une expression dont la valeur est affectée à la lvalue.
• La valeur finale de l’expression d’affectation est la valeur de la lvalue après affectation.
• La priorité de cet opérateur est inférieure à celle de tous les opérateurs arithmétiques et les opérateurs de
comparaison.
• Si les opérandes sont de types différents, il y a une conversion systématique de l’expression dans le type de
la lvalue. Cette conversion peut entraîner à une dégradation de la valeur convertie. Par exemple, une valeur
de type float peut être tronquée si elle est affectée à une lvalue de type entier.
• Contrairement à tous ceux que nous avons rencontrés jusqu'ici, cet opérateur d'affectation possède une
associativité de droite à gauche.
Les opérateurs et les expressions
• Les opérateurs d'incrémentation et de décrémentation
On distingue deux opérateurs unaires:
• L’opérateur d’incrémentation noté ++
• L’opérateur de décrémentation noté - -
Ils ont pour effet d’incrémenter ou de décrémenter de 1 la valeur d'une variable (ou plus généralement d'une Ivalue).

On dit que ++ est :


• un opérateur de pré-incrémentation lorsqu'il est placé à gauche de la Ivalue sur laquelle il porte (++i), la valeur de
l’expression d’incrémentation est celle de la ``lvalue`` après incrémentation.
• un opérateur de post-incrémentation lorsqu'il est placé à droite de la Ivalue sur laquelle il porte (i++), la valeur de
l’expression d'incrémentation est celle de la ``lvalue`` avant incrémentation.
Exemple:
int i = 5;
i++ équivaut à i = i + 1
i devient égale à 6
la valeur de cette expression est 5
++i équivaut á i = i + 1
i devient égal á 6
la valeur de cette expression est 6.
Les opérateurs et les expressions
• Les opérateurs d'incrémentation et de décrémentation
On dit que -- est :
• un opérateur de pré-décrémentation lorsqu'il est placé à gauche de la Ivalue sur laquelle il porte (--i), la valeur de
l’expression de décrémentation est celle de la ``lvalue`` après décrémentation.
• un opérateur de post-décrémentation lorsqu'il est placé à droite de la Ivalue sur laquelle il porte (i--), la valeur de
l’expression de décrémentation est celle de la ``lvalue`` avant décrémentation.
Exemple:
int i = 4;
i-- équivaut à i = i - 1
i devient égale à 3
la valeur de cette expression est 4
--i équivaut á i = i - 1
i devient égal á 3
la valeur de cette expression est 3.
Ces opérateurs sont de plus haute priorité que les opérateurs arithmétiques. Alors
L’expression 3 * i++ * j-- + k++ équivaut à 3 * (i++)n* (j--) + ( k++)
Les opérateurs et les expressions
• Les opérateurs d'affectation élargie
C permet de condenser les affectations de la forme :
Ivalue = Ivalue opérateur expression
en :
Ivalue opérateur= expression
Cette possibilité concerne tous les opérateurs binaires arithmétiques et de manipulation de bits. Voici la liste complète de
tous ces nouveaux opérateurs nommés « opérateurs d'affectation élargie »
+= -= *= /= %=
Exemple:
int i,k;
i += k équivaut à i = i + k
i *= k équivaut à i = i * k.
Les opérateurs et les expressions
• L'opérateur de cast
• le programmeur peut forcer la conversion d'une expression quelconque dans un type de son choix, à l'aide
d'un opérateur un peu particulier nommé en anglais « cast ».

• Si, par exemple, n et p sont des variables entières, l'expression : (double) ( n/p ) aura comme valeur celle de
l'expression entière n/p convertie en double.

• La notation (double) correspond en fait à un opérateur unaire dont le rôle est d'effectuer la conversion dans
le type double de l'expression sur laquelle il porte. Notez bien que cet opérateur force la conversion du
résultat de l'expression et non celle des différentes valeurs qui concourent à son évaluation.

• D'une manière générale, il existe autant d'opérateurs de « cast » que de types différents. Leur priorité
élevée fait qu'il est généralement nécessaire de placer entre parenthèses l'expression concernée. Ainsi,
l'expression (double) n/p conduirait d'abord à convertir n en double.
Les opérateurs et les expressions
• L'opérateur conditionnel
• Considérons l'instruction suivante :
if ( a>b )
max = a ;
else
max = b ;
• Elle attribue à la variable max la plus grande des deux valeurs de a et de b. La valeur de max pourrait être définie par cette
phrase : Si a>b alors a sinon b

• En langage C, il est possible, grâce à l'aide de l'opérateur conditionnel, de traduire presque littéralement la phrase ci-
dessus de la manière suivante : max = a>b ? a : b

• L’opérateur conditionnel est un opérateur ternaire mettant en relation 3 expressions ou opérandes (a>b, a et b)
• Voici un autre exemple d'une expression calculant la valeur absolue de 3*a + 1 :
3*a+1 >0 ? 3*a+1 : -3*a-1
• Sa priorité est faible, relativement aux autres opérateurs.
Les opérateurs et les expressions
• L'opérateur séquentiel
L’opérateur séquentiel noté "," permet d’exprimer plusieurs calculs successifs au sein d’une même expression.

Exemple:
L’expression a*b, i + j
1. évalue a * b
2. puis i + j
3. prend comme valeur la dernière calculée ( la valeur de i + j )

L’expression i ++, j = i + k
1. incrémente la valeur de i
2. puis évalue j = i + k.

L’opérateur séquentiel permet de regrouper plusieurs instructions en une seule.


Les opérateurs et les expressions
• L'opérateur sizeof
Son emploi ressemble à celui d’une fonction. Il fournit la taille ( en octet ) de son paramètre. Cet opérateur
peut être appliqué soit à une variable soit à un type .

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 :
• 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).
Les opérateurs et les expressions
• Récapitulatif des priorités de tous les opérateurs
Le tableau ci-après fournit la liste complète des opérateurs du langage C, classés par ordre de priorité décroissante,
accompagnés de leur mode d'associativité.
Les opérateurs et les expressions
• Exercices 1
Soit les déclarations suivantes :
int n = 10 , p = 4 ;
long q = 2 ;
float x = 1.75 ;
Donner le type et la valeur de chacune des expressions suivantes :
a) n + q g) q + 3 * (n > p)
b) n + x h) q && n
c) n % p +q i) (q-2) && (n-10)
d) n < p j) x * (q==2)
e) n >= p k) x *(q=5)
f) n > q
Les opérateurs et les expressions
• Exercices 2
Quels résultats fournit le programme suivant ?
Les opérateurs et les expressions
• Exercices 3
Quels résultats fournit le programme suivant ?
Chapitre IV

Les entrées-sorties
conversationnelles
Les entrées-sorties conversationnelles
• Les sorties conversationnelles
Afin d’afficher un caractère ou même un texte (on préfère le terme de « chaîne de caractères ») à l’écran, il faut
utiliser des fonctions. Une fonction, en simplifiant un peu, est un morceau de code exécutant des instructions.
Des instructions qui permettent d’effectuer des opérations (avec par exemple des fonctions mathématiques)
sur des variables ou encore d’écrire du texte à l’écran par exemple.

Nous allons voir trois fonctions d’affichage de données dans ce chapitre :


• printf pour écrire une chaîne de caractères formatée ;
• puts pour écrire une chaîne de caractères toute simple ;
• putchar pour écrire un caractère.
Les entrées-sorties conversationnelles
• La fonction printf
La fonction printf affiche donc une chaîne de caractères (c'est-à-dire du texte) à l’écran. On l'utilise comme
ceci :
printf (param_1, param_2, param_3,..., param_n)

où param_1 à param_n est une suite d'au moins un paramètre transmis à la fonction, séparés par des ','.

• param_1 : est obligatoire c'est une chaîne de caractères qui comporte des caractères à afficher tels quels et
éventuellement des consignes de formatage pour les autres paramètres (s'il y en a). Il doit y avoir autant de
consignes que de paramètres restant à afficher.
• Le résultat est tel que l'on affiche les arguments param_2, param_3,..., param_n aux formats spécifiés dans
param_1.
• Une consigne de formatage commence toujours par le caractère '%', suivi d'autres caractères qui définissent
le format d'affichage. C'est donc une séquence d'échappement.
Les entrées-sorties conversationnelles
• La fonction printf
Voici les indicateurs de conversions de la norme C89 :
Les entrées-sorties conversationnelles
• La fonction printf (gabarit d'affichage)
• Par défaut, les entiers sont affichés avec le nombre de caractères nécessaires (sans espaces avant ou après). Les flottants
sont affichés avec six chiffres après le point.
• Un nombre placé après % dans le code de format précise un gabarit d'affichage, c'est-à-dire un nombre minimal de
caractères à utiliser. Si le nombre peut s'écrire avec moins de caractères, printf le fera précéder d'un nombre suffisant
d'espaces. (Dans les exemples ci-dessous le symbole ^ représente un espace)
Les entrées-sorties conversationnelles
• La fonction printf (la précision)
• Vous pouvez toujours préciser la précision de l’affichage. Une précision, sous la forme d’un point ('.') suivi par un nombre,
indique donc le nombre de chiffres qu’il y aura derrière la virgule. Voici quelques exemples :
Les entrées-sorties conversationnelles
• La fonction printf (Tabulations et compagnie)
• Afin d’afficher une tabulation ou encore un retour à la ligne, on utilise un caractère d'échappement.
printf("La valeur de la variable\n\t x est : %f\n\t y = %d", x, y);
La valeur de la variable
x est : 42.424340
y=1

• '\n' et '\t' font partie de ces caractères. Voici un petit tableau qui en liste quelques-uns parmi les plus utilisés :
Les entrées-sorties conversationnelles
• Putchar et puts
L'expression :
putchar (c)
joue le même rôle que :
printf ( " %c", c)

• Son exécution est toutefois plus rapide, dans la mesure où elle ne fait pas appel au mécanisme d'analyse de
format. Notez qu'en toute rigueur putchar n'est pas une vraie fonction mais une macro.

• L’utilisation de la fonction puts est plus simple puisqu’elle ne se contente d'afficher que des chaînes de
caractères simples.
puts("Salut les zeros !");
Les entrées-sorties conversationnelles
• Interagir avec l’utilisateur (Entrée conversationnelle)
Maintenant que nous savons déclarer, utiliser et même afficher des variables, nous sommes fin prêts pour
interagir avec l’utilisateur. Nous allons voir comment en récupérer grâce à la fonction scanf, dont l’utilisation
est assez semblable à printf.
scanf("%[lettre]", &variable_dans_laquelle_on_va_mettre_notre_valeur);

La fonction scanf a besoin de connaitre l’emplacement en mémoire de nos variables afin de les modifier. Afin
d’effectuer cette opération, on utilise le symbole &.
Exemple:
int age;

printf("Donnez votre age :");


scanf("%d", &age);
printf("Vous avez %d an(s) !\n", age);
Les entrées-sorties conversationnelles
• La fonction scanf
Voici quelques exemples dans lesquels nous supposons que n et p sont de type int, tandis que c est de type
char. Nous fournissons, pour chaque appel de scanf, des exemples de réponses possibles ( ^ désigne un espace
et @ une fin de ligne) et, en regard, les valeurs effectivement lues.
Les entrées-sorties conversationnelles
• Getchar et gets
L'expression :
c = getchar()
joue le même rôle que :
scanf ( "%c", &c)

tout en étant plus rapide puisque ne faisant pas appel au mécanisme d'analyse d'un format.
En toute rigueur, getchar est une macro (comme putchar) dont les instructions figurent dans stdio.h. Là encore,
l'omission d'une instruction #include appropriée conduit à une erreur à l'édition de liens.
Les entrées-sorties conversationnelles
• Exercice
Quels seront les résultats fournis par ce programme ?
Chapitre V

Les instructions de
contrôle
Les instructions de contrôle
• Instructions de contrôle
Le langage C dispose d’instructions de contrôle permettant de réaliser :

• des choix :
• L’instruction conditionnelle if…else…
• L’instruction d’aiguillage ou de choix switch…case…default…

• des boucles (les instruction répétitives) :


• while…do…
• do…while…
• for…

• des branchements (Les instructions de branchement inconditionnel)


• goto
• break ( associé aux boucles)
• continue ( associé aux boucles)
• return
Les instructions de contrôle
• L'instruction if
L’instruction conditionnelle if permet de tester une condition puis d'exécuter une action parmi deux actions
possibles.
Syntaxe:
if ( expression) if ( expression)
instructions1; instructions1;
else
instructions2 ;
• Instructions1 et instructions2 sont des instructions quelconques qui peuvent être soit une instruction soit
un bloc d’instructions placées entre { et }.
• Si l’expression a une valeur non nulle ( vraie) alors instructions1 est exécutée sinon instructions2 est
exécutée.
Les instructions de contrôle
• L'instruction if
Exemple1
int a,b ;

if ( a<b )
max = b ;
else
max = a ;

Exemple 2
int a,b ;

if (( a < = b ) && ( b<= c)) printf( “ordonne”);
Les instructions de contrôle
• L'instruction if
Cas d’imbrications des instructions if…else
Le premier else rencontré est associé avec le plus proche if qui le précède:
• 1ère forme d’imbrication :
if (a <= b)
if ( b<= c) {
printf( “ ordonnée” );
max = c; }
else
printf( “ non ordonnée” );

dans cet exemple, dans le cas où l’expression ( a<=b ) est fausse, rien n’est affiché .
• 2ème forme d’imbrication :
if (heure >= 0) && ( heure < 12)
printf( “ bonjour” );
else if ((heure >= 12) && ( heure < 18))
printf( “ bon pares midi” );
else if ((heure >= 18) && ( heure < 24 ))
printf (“ bonsoir” );
else
printf( “ erreur” );
Les instructions de contrôle
• L'instruction if
Exemple
Les instructions de contrôle
• L'instruction if
Exercice :
Ecrire un programme qui compare les valeurs de 3 entiers et affiche le max.
Les instructions de contrôle
• L'instruction switch
• L’instruction switch est une instruction de choix multiple. Elle permet d’évaluer une expression puis
d'exécuter une action parmi plusieurs actions étiquetées.
• Si la valeur de l’expression correspond à une des étiquettes, l’action correspondante est exécutée .
Syntaxe:
Switch ( expression)
{
case constante1 : [ instructions; ]
………….
case constante : [ instructions; ]
………
[default : instructions; ]
}

• « expression » doit être une expression entière


• « la constante » doit être une constante entière( de type int, char, short,long,unsigned). Par contre
« default » est facultatif.
Les instructions de contrôle
• L'instruction switch
L’expression est comparée successivement( de haut en bas) aux constantes spécifiées après chaque “case”.
S’il y a égalité, alors les instructions correspondantes à ce « case » sont exécutées.
Dans le cas où aucune égalité n’est vérifiée, les instructions spécifiées après “ default” sont exécutées.

Pour sortir de l’instruction switch délimitée par { et } et continuer en séquence, on doit utiliser l’instruction
break .

Exemple:
char c;

switch (c)
{
case ‘a’ : printf( “ lettre a” ); break;
case ‘b’ : printf ( “ lettre b” ); break;
default : printf ( “ lettre inconnue” );
}
Les instructions de contrôle
• L'instruction switch
Exemple:
Les instructions de contrôle
• L'instruction switch
Exercice :
Écrire un programme permettant d'afficher le jour en toute lettres selon son numéro saisi au clavier.
Les instructions de contrôle
• L'instruction do... while

Elle permet de répéter une ou plusieurs actions tant que la condition spécifiée n’est pas vérifiée.

Syntaxe :
Do
instructions
while ( expression) ;

• Instructions peut être soit une seule instruction suivie de ; soit un bloc d’instructions entre { et } .
• L’expression est évaluée après avoir exécutée au moins une fois instructions.
• Si la valeur de l’expression est non nulle ( vraie), cette exécution est répétée sinon l’itération se termine.
Les instructions de contrôle
• L'instruction do... while

Exemple :
float note;
do{
printf(“saisir la note”) ;
scanf(“%f”,&note);
}while (note<0 || note>20)
Les instructions de contrôle
• L'instruction do... while

Exemple 2:
Les instructions de contrôle
• L'instruction while

Tant qu’une condition spécifiée n’est pas vérifiée, elle permet de répéter une ou plusieurs actions.

Syntaxe :
while ( expression )
instructions

Instructions peut être soit une seule instruction soit un bloc d’instructions entre { et } .

• L’expression est évaluée avant d'exécuter instructions.


• Tant que la valeur de l’expression est non nulle ( vraie), instructions est exécutée, sinon l’itération se
termine.
Les instructions de contrôle
• L'instruction while

Exemple :
int i;
while (i<10){
printf(“%d”,i) ;
i++;
}
Les instructions de contrôle
• L'instruction while

Exemple 2:
Les instructions de contrôle
• L'instruction for

L’instruction for est une instruction de boucle faisant intervenir l’initialisation, le test de limite et
l’incrémentation en une seule action.

Syntaxe:
for ( [expr1] ; [expr2] ; [expr3] )
Instructions;

• “ instructions” peut être une instruction composée, et sera dans ce cas délimitée par { et }.
• “ expr1” est une expression ( une initialisation) qui ne sera exécutée qu’une seule fois au début.
• “expr2” est une expression dont le résultat détermine la fin de la boucle.
• Tant que sa valeur est non nulle ( vraie), la boucle continue.
• “ expr3” est une expression ( en général) qui sera exécutée à chaque itération.
Les instructions de contrôle
• L'instruction for

Exemple :
int i;
for (i=1;i<=5;i++){
printf(“veuillez saisir le nombre %d”,i) ;
scanf(“%d”,&a) ;
printf(“%d”,a*a)
}
Les instructions de contrôle
• L'instruction for

Exemple 2:
Les instructions de contrôle
• L'instruction for

Exercices :
1. Ecrire un algorithme qui demande un nombre de départ, et qui calcule sa factorielle.
2. Ecrire un algorithme qui demande un nombre, calcule et affiche la Somme 𝑛𝑖=1 𝑖 2
3. Ecrire un algorithme qui permet d’afficher un triangle rempli d'étoiles, s'étendant sur un nombre de lignes
fourni en donnée et se présentant comme dans cet exemple :
*
**
***
****
*****
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction break
• Elle peut être utilisée dans les boucles ou dans une instruction switch. Elle permet d’interrompre le
déroulement de la structure où elle a été appelée.
• Dans le cas des boucles ou plusieurs ‘switch ’ imbriqués, l’instruction ‘break’ n’a d’effet que sur la boucle
où elle a été définie.

Exemple:
int i, nbr;
i=0;
while (i<3)
{ printf(“saisir votre nombre);
scanf(“%d”,&nbr);
if ( nbr == 0)
break;
i++;
}
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction break
Exemple:
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction continue
• Elle peut être utilisée dans les boucles .
• Elle permet de sauter une séquence d’instructions sans sortir de la boucle.
• Dans le cas des boucles imbriquées, l’instruction ‘continue’ n’a d’effet que sur la boucle où elle a été définie.
Exemple:

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


{
if( i % 2)
continue;
printf(“%d”,i);
}
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction continue
Exemple:
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction goto
Elle permet le branchement inconditionnel vers une instruction spécifiée par une étiquette dans le
programme.
Syntaxe:
goto étiquette;
….
étiquette: …..
Exemple:

while ( i<10)
{ ….
If ( a==0)
goto fin;
….
};
fin: printf( “ fin de boucle : a=0” );
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction goto
Exemple:
Les instructions de contrôle
• Les instructions de branchement inconditionnel
Exercices :
Qu’affiche le code suivant :
Chapitre VI

Les tableaux
Les tableaux
• Les tableaux
• Les tableaux sont certainement les variables structurées les plus populaires. Ils sont disponibles dans tous
les langages de programmation et servent à résoudre une multitude de problèmes. Dans une première
approche, le traitement des tableaux en C ne diffère pas de celui des autres langages de programmation.
Nous allons cependant voir plus loin (Chapitre suivant. Les Pointeurs), que le langage C permet un accès
encore plus direct et plus rapide aux données d'un tableau.
• Les chaînes de caractères sont déclarées en C comme tableaux de caractères et permettent l'utilisation d'un
certain nombre de notations et de fonctions spéciales.
• On nomme ainsi un ensemble d'éléments de même type désignés par un identificateur unique ; chaque
élément est repéré par un indice précisant sa position au sein de l'ensemble.
Les tableaux
• Les tableaux à une dimension
Un tableau (uni-dimensionnel) A est une variable structurée formée d'un nombre entier N de variables simples
du même type, qui sont appelées les composantes du tableau. Le nombre de composantes N est alors
la dimension du tableau.

Exemple

La déclaration
int tab[12]={31,28,31,30,31,30,31,31,30,31,30,31};

• définit un tableau du type int de dimension 12. Les 12 composantes sont initialisées par les valeurs
respectives 31, 28, 31, ... , 31.
• On peut accéder à la première composante du tableau par tab[0], à la deuxième composante par tab[1], . . .
, à la dernière composante par tab[11].
Les tableaux
• Les tableaux à une dimension
En C, le nom d'un tableau est le représentant de l'adresse du premier élément du tableau. Les adresses des
autres composantes sont calculées (automatiquement) relativement à cette adresse.

Exemple:

short A[5] = {1200, 2300, 3400, 4500, 5600};

Si un tableau est formé de N composantes et si une composante a besoin de M octets en mémoire, alors le
tableau occupera de N*M octets.
Exemple
En supposant qu'une variable du type long occupe 4 octets (c.-à-d: sizeof(long)=4), pour le tableau T déclaré
par: long T[15]; C réservera N*M = 15*4 = 60 octets en mémoire.
Les tableaux
• Les tableaux à une dimension
• Initialisation

Lors de la déclaration d'un tableau, on peut initialiser les composantes du tableau, en indiquant la liste des valeurs
respectives entre accolades.
Exemples
int A[5] = {10, 20, 30, 40, 50};
float B[4] = {-1.05, 3.33, 87e-5, -12.3E4};

Il faut évidemment veiller à ce que le nombre de valeurs dans la liste corresponde à la dimension du tableau. Si la liste ne
contient pas assez de valeurs pour toutes les composantes, les composantes restantes sont initialisées par zéro.

• Réservation automatique

Si la dimension n'est pas indiquée explicitement lors de l'initialisation, alors l'ordinateur réserve automatiquement le nombre
d'octets nécessaires.
Exemples
int A[] = {10, 20, 30, 40, 50};
Les tableaux
• Les tableaux à une dimension
En déclarant un tableau par:
int A[5];
nous avons défini un tableau A avec cinq composantes, auxquelles on peut accéder par: A[0], A[1], ... , A[4]

Exemples

MAX = (A[0]>A[1]) ? A[0] : A[1];


A[4] *= 2;

En C,
• l'accès au premier élément du tableau se fait par T[0]
• l'accès au dernier élément du tableau se fait par T[N-1]
Les tableaux
• Les tableaux à une dimension
Exemple
Les tableaux
• Les tableaux à une dimension
Exercices :
• Ecrire un programme qui lit la dimension N d'un tableau T du type int (dimension maximale: 50
composantes), remplit le tableau par des valeurs entrées au clavier et affiche le tableau. Calculer et afficher
ensuite la somme des éléments du tableau.

• Ecrire un programme qui lit la dimension N d'un tableau T du type int (dimension maximale: 50
composantes), remplit le tableau par des valeurs entrées au clavier et affiche le tableau. Ranger ensuite les
éléments du tableau T dans l'ordre inverse sans utiliser de tableau d'aide. Afficher le tableau résultant.
Idée: Echanger les éléments du tableau à l'aide de deux indices qui parcourent le tableau en commençant
respectivement au début et à la fin du tableau et qui se rencontrent en son milieu.
Les tableaux
• Les tableaux à deux dimensions
En C, un tableau à deux dimensions A est à interpréter comme un tableau (uni-dimensionnel) de dimension L
dont chaque composante est un tableau (uni-dimensionnel) de dimension C.
On appelle L le nombre de lignes du tableau et C le nombre de colonnes du tableau. L et C sont alors les
deux dimensions du tableau. Un tableau à deux dimensions contient donc L*C composantes.

Exemple
Considérons un tableau NOTES à une dimension pour mémoriser les notes de 20 élèves d'une classe dans un
devoir:
int NOTE[20] = {45, 34, ... , 50, 48};

Pour mémoriser les notes des élèves dans les 10 devoirs d'un trimestre, nous pouvons rassembler plusieurs de
ces tableaux uni-dimensionnels dans un tableau NOTES à deux dimensions :

int NOTE[10][20] = { {45, 34, ... , 50, 48},


{39, 24, ... , 49, 45},
... ... ...
{40, 40, ... , 54, 44} } ;
Les tableaux
• Les tableaux à deux dimensions
Initialisation
Lors de la déclaration d'un tableau, on peut initialiser les composantes du tableau, en indiquant la liste des valeurs
respectives entre accolades. A l'intérieur de la liste, les composantes de chaque ligne du tableau sont encore une fois
comprises entre accolades. Pour améliorer la lisibilité des programmes, on peut indiquer les composantes dans plusieurs
lignes.

Exemples
int A[3][10] ={{ 0,10,20,30,40,50,60,70,80,90},
{10,11,12,13,14,15,16,17,18,19},
{ 1,12,23,34,45,56,67,78,89,90}};

float B[3][2] = {{-1.05, -1.10 },


{86e-5, 87e-5 },
{-12.5E4, -12.3E4}};
Lors de l'initialisation, les valeurs sont affectées ligne par ligne en passant de gauche à droite. Nous ne devons pas
nécessairement indiquer toutes les valeurs: Les valeurs manquantes seront initialisées par zéro. Il est cependant défendu
d'indiquer trop de valeurs pour un tableau.
Les tableaux
• Les tableaux à deux dimensions
Exercices :

• Ecrire un programme qui réalise l'addition de deux matrices A et B de mêmes dimensions N et M.


• Ecrire un programme qui construit et affiche une matrice carrée unitaire U de dimension N. Une matrice
unitaire est une matrice, telle que:
1 𝑠𝑖 𝑖 = 𝑗
𝑢𝑖𝑗 =
0 𝑠𝑖 𝑖 ≠ 𝑗
Chapitre VII

Les pointeurs
Les pointeurs
• 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. Pour
retrouver une variable, il suffit donc de connaître l'adresse de l'octet où elle est stockée (ou, s'il s'agit d'une
variable qui recouvre plusieurs octets contigus, l'adresse du premier de ces octets). Pour des raisons évidentes
de lisibilité, on désigne souvent les variables par des identificateurs, et non par leur adresse. C'est le
compilateur qui fait alors le lien entre l'identificateur d'une variable et son adresse en mémoire. Toutefois, il est
parfois très pratique de manipuler directement une variable par son adresse.
Les pointeurs
• Notion d‘adresse
On appelle Lvalue (left value) tout objet pouvant être placé à gauche d'un opérateur d'affectation. Une Lvalue
est caractérisée par :
• son adresse, c'est-à-dire l'adresse-mémoire à partir de laquelle l'objet est stocké ;
• sa valeur, c'est-à-dire ce qui est stocké à cette adresse.
Dans l'exemple,
int i, j;
i = 3;
j = i;
Si le compilateur a placé la variable i à l'adresse 4831836000 en mémoire, et la variable j à l'adresse
4831836004, on a

objet adresse valeur


i 4831836000 3
j 4831836004 3
Les pointeurs
• Notion de pointeur
Un pointeur est un objet (Lvalue) dont la valeur est égale à l'adresse d'un autre objet. On déclare un pointeur
par l'instruction :
type *nom-du-pointeur;
où type est le type de l'objet pointé.

• Cette déclaration déclare un objet dont la valeur est l'adresse d'un autre objet. L'identificateur nom-du-
pointeur est donc en quelque sorte un identificateur d'adresse. Comme pour n'importe quelle Lvalue, sa
valeur est modifiable.
• Le type d'un pointeur dépend du type de l'objet vers lequel il pointe.
• En effet, pour un pointeur sur un objet de type char, la valeur donne l'adresse de l'octet où cet objet est
stocké. Par contre, pour un pointeur sur un objet de type int, la valeur donne l'adresse du premier des (4
octets) où l'objet est stocké.
Les pointeurs
• Notion de pointeur
Dans l'exemple suivant, on définit un pointeur p qui pointe vers un entier i :
int i = 3;
int *p;
p = &i;
On se trouve dans la configuration

objet adresse valeur


i 4831836000 3
p 4831836004 4831836000
Les pointeurs
• Notion de pointeur
• L'opérateur unaire d'indirection * permet d'accéder directement à la valeur de l'objet pointé. Ainsi, si p est
un pointeur vers un entier i, *p désigne la valeur de i. Cela signifie en particulier que toute modification de
*p modifie i.
• On peut donc dans un programme manipuler à la fois les objets p et *p.

Comparons par exemple les deux programmes suivants :

main() main()
{ {
int i = 3, j = 6; int i = 3, j = 6;
int *p1, *p2; int *p1, *p2;
p1 = &i; p1 = &i;
p2 = &j; p2 = &j;
*p1 = *p2; p1 = p2;
} }
Les pointeurs
• Notion de pointeur
Avant la dernière affectation de chacun de ces programmes, on est dans une configuration du type :
objet adresse valeur
i 4831836000 3
j 4831836004 6
p1 4831835984 4831836000
p2 4831835992 4831836004
Après l'affectation *p1 = *p2; du premier programme, on a
objet adresse valeur
i 4831836000 6
j 4831836004 6
p1 4831835984 4831836000
p2 4831835992 4831836004

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


objet adresse valeur
i 4831836000 3
j 4831836004 6
p1 4831835984 4831836004
p2 4831835992 4831836004
Les pointeurs
• Arithmétique des pointeurs
La valeur d'un pointeur étant un entier, on peut lui appliquer un certain nombre d'opérateurs arithmétiques
classiques. Les seules opérations arithmétiques valides sur les pointeurs sont :
• l'addition d'un entier à un pointeur. Le résultat est un pointeur de même type que le pointeur de
départ ;
• la soustraction d'un entier à un pointeur. Le résultat est un pointeur de même type que le pointeur de
départ ;
• la différence de deux pointeurs pointant tous deux vers des objets de même type. Le résultat est un
entier.

Notons que la somme de deux pointeurs n'est pas autorisée.

Si i est un entier et p est un pointeur sur un objet de type int, l'expression p + i désigne un pointeur sur un
objet de type int dont la valeur est égale à la valeur de p incrémentée de i * sizeof(int). Il en va de même pour
la soustraction d'un entier à un pointeur, et pour les opérateurs d'incrémentation et de décrémentation ++ et --
Les pointeurs
• Allocation dynamique
Avant de manipuler un pointeur, et notamment de lui appliquer l'opérateur d'indirection *, il faut l'initialiser.
Sinon, par défaut, la valeur du pointeur est égale à une constante symbolique notée NULL définie dans stdio.h.
En général, cette constante vaut 0. Le test p == NULL permet de savoir si le pointeur p pointe vers un objet.

On peut initialiser un pointeur p par une affectation sur p. Par exemple, on peut affecter à p l'adresse d'une
autre variable. Il est également possible d'affecter directement une valeur à *p. Mais pour cela, il faut d'abord
réserver à *p un espace-mémoire de taille adéquate. L'adresse de cet espace-mémoire sera la valeur de p.
Cette opération consistant à réserver un espace-mémoire pour stocker l'objet pointé s'appelle allocation
dynamique. Elle se fait en C par la fonction malloc de la librairie standard stdlib.h. Sa syntaxe est:
malloc(nombre-octets)

Cette fonction retourne un pointeur de type char * pointant vers un objet de taille nombreoctets octets. Pour
initialiser des pointeurs vers des objets qui ne sont pas de type char, il faut convertir le type de la sortie de la
fonction malloc à l'aide d'un cast. L'argument nombre-octets est souvent donné à l'aide de la fonction sizeof()
qui renvoie le nombre d'octets utilisés pour stocker un objet.
Les pointeurs
• Allocation dynamique
Ainsi, pour initialiser un pointeur vers un entier, on écrit :
#include <stdlib.h>

int *p;
p = (int*)malloc(sizeof(int));

Exemple
#include <stdio.h>
#include <stdlib.h>
main()
{
int i = 3;
int *p;
printf("valeur de p avant initialisation = %ld\n",p);
p = (int*)malloc(sizeof(int));
printf("valeur de p apres initialisation = %ld\n",p);
*p = i;
printf("valeur de *p = %d\n",*p);
}
Les pointeurs
• Allocation dynamique
La fonction malloc permet également d'allouer un espace pour plusieurs objets contigus en mémoire. On peut
écrire par exemple
#include <stdio.h>
#include <stdlib.h>
main()
{
int i = 3;
int j = 6;
int *p;
p = (int*)malloc(2 * sizeof(int));
*p = i;
*(p + 1) = j;
printf("p = %ld \t *p = %d \t p+1 = %ld \t *(p+1) = %d
\n",p,*p,p+1,*(p+1));
}
Les pointeurs
• Allocation dynamique
• La fonction calloc de la librairie stdlib.h a le même rôle que la fonction malloc mais elle initialise en plus
l'objet pointé *p à zéro. Sa syntaxe est
calloc(nb-objets,taille-objets)

• Enfin, lorsque l'on n'a plus besoin de l'espace-mémoire alloué dynamiquement (c'est-à-dire quand on
n'utilise plus le pointeur p), il faut libérer cette place en mémoire. Ceci se fait à l'aide de l'instruction free
qui a pour syntaxe
free(nom-du-pointeur);
• A toute instruction de type malloc ou calloc doit être associée une instruction de type free.
Les pointeurs
• Pointeurs et tableaux
• L'usage des pointeurs en C est, en grande partie, orienté vers la manipulation des tableaux.
• Tout tableau en C est en fait un pointeur constant. Dans la déclaration int tab[10]; tab est un pointeur constant (non
modifiable) dont la valeur est l'adresse du premier élément du tableau. Autrement dit, tab a pour valeur &tab[0]. On peut
donc utiliser un pointeur initialisé à tab pour parcourir les éléments du tableau.
Exemple :
#define N 5
int tab[5] = {1, 2, 6, 0, 7};
main()
{
int i;
int *p;
p = tab;
for (i = 0; i < N; i++)
{
printf(" %d \n",*p);
p++;
}
}
Les pointeurs
• Pointeurs et tableaux
Toutefois, la manipulation de tableaux, et non de pointeurs, possède certains inconvénients dûs au fait qu'un
tableau est un pointeur constant. Ainsi
• on ne peut pas créer de tableaux dont la taille est une variable du programme,
• on ne peut pas créer de tableaux bidimensionnels dont les lignes n'ont pas toutes le même nombre
d'éléments.

Les deux différences principales entre un tableau et un pointeur sont


• un pointeur doit toujours être initialisé, soit par une allocation dynamique, soit par affectation d'une
expression adresse, par exemple p = &i ;
• un tableau n'est pas une Lvalue ; il ne peut donc pas figurer à gauche d'un opérateur d'affectation. En
particulier, un tableau ne supporte pas l'arithmétique (on ne peut pas écrire tab++;)
Les pointeurs
• Exercices
Soit P un pointeur qui "pointe" sur un tableau A:
int A[] = {12, 23, 34, 45, 56, 67, 78, 89, 90};
int *P;
P = A;
Quelles valeurs ou adresses fournissent ces expressions:
*P+2 A+3
*(P+2) &A[7]-P
&P+1 P+(*P-10)
&A[4]-3 *(P+*(P+8)-A[7])
Les pointeurs
• Exercices
Ecrire un programme qui range les éléments d'un tableau A du type int dans l'ordre inverse. Le programme
utilisera des pointeurs P1 et P2 et une variable numérique AIDE pour la permutation des éléments.
Les pointeurs
• Exercices
Écrire, de deux façons différentes, un programme qui lit 10 nombres entiers dans un tableau avant d'en
rechercher le plus grand et le plus petit :
• en utilisant uniquement le « formalisme tableau »,
• en utilisant le « formalisme pointeur », chaque fois que cela est possible.
Bibliographie

• The C Programming Language (Brian Kernighan and Dennis Ritchie)


• Programmer en langage C (Delannoy,Claude)
• C Programming: A Modern Approach (K. N. King)
• Programmation en langage C (Anne Canteaut)
• Introduction a la programmation en ANSI-C (F.Faber )

Vous aimerez peut-être aussi