0% ont trouvé ce document utile (0 vote)
25 vues78 pages

Cours de Programmation en C - MIP-I

Le document est un cours sur la programmation en langage C, destiné aux étudiants de la filière MIP-I à l'Université Sultan Moulay Slimane pour l'année universitaire 2025-2026. Il couvre divers sujets, y compris l'environnement de programmation, les types de données, les opérateurs, les structures de contrôle, la lecture et l'écriture de données, ainsi que la programmation modulaire et les fonctions. Le cours est structuré en plusieurs chapitres détaillant les concepts fondamentaux et les exemples pratiques.

Transféré par

kouchaneilyass4
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
25 vues78 pages

Cours de Programmation en C - MIP-I

Le document est un cours sur la programmation en langage C, destiné aux étudiants de la filière MIP-I à l'Université Sultan Moulay Slimane pour l'année universitaire 2025-2026. Il couvre divers sujets, y compris l'environnement de programmation, les types de données, les opérateurs, les structures de contrôle, la lecture et l'écriture de données, ainsi que la programmation modulaire et les fonctions. Le cours est structuré en plusieurs chapitres détaillant les concepts fondamentaux et les exemples pratiques.

Transféré par

kouchaneilyass4
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Université Sultan Moulay Slimane

Faculté Polydisciplinaire
Filière MIP-I
- Béni Mellal -

Cours MIP-I (S3)

Programmation en Langage C

••••• Version 1.0 Prof. Said SAFI

Année Universitaire : 2025-2026


TABLE DES MATIÈRES

Introduction générale 7

1 L’environnement et les bibliothèques 9


1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Programme C : Forme générale . . . . . . . . . . . . . . . . . . . . . . . 10
1.2.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Les types de base du langage C . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.1 Les entiers : int . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.2 Les réels :float . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.3 Les caractère :char . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4 Commentaires, noms et constantes . . . . . . . . . . . . . . . . . . . . . 13
1.4.1 Les commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.2 les noms d’objets . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.3 les constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.5 Déclaration de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.5.1 Les tableaux statiques . . . . . . . . . . . . . . . . . . . . . . . . 14
1.5.2 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6 Les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6.1 Exemple 1 : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6.2 Exemple 2 : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2 Opérateurs et expressions 17
2.1 les opérateurs arithmétiques . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2 les opérateurs incrémentaux . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3 les opérateurs bit à bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4 Les opérateurs de décalage . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 les opérateurs de comparaison . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6 les opérateurs logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.7 les opérateurs d’affectation . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.8 l’opérateur conditionnel . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

1
2.9 les opérateurs sur les pointeurs, tableaux et structures . . . . . . . . . . . 22
2.10 conversions de type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.10.1 conversions implicites . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.10.2 conversions explicites . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.11 conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Les structures de contrôle : Boucles et tests 25


3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2 Les structures de boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2.1 Les structures while . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.2 Les structures for . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.3 les instructions de contrôles de boucles . . . . . . . . . . . . . . . . . . . 28
3.3.1 les structures de choix . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.2 la structure de choix multiples . . . . . . . . . . . . . . . . . . . . 29
3.4 conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

4 Lecture et écriture des données 31


4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Écriture formatée de données . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2.1 Exemple 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.2.2 Exemple 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.2.3 Arguments rationnels . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.2.4 Arguments rationnels . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2.5 Largeur minimale pour les entiers . . . . . . . . . . . . . . . . . . 35
4.2.6 Largeur minimale et précision pour les rationnels . . . . . . . . . 35
4.3 Lecture formatée de données . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.3.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.4 Impression et lecture de caractères . . . . . . . . . . . . . . . . . . . . . 38
4.5 conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

5 La programmation modulaire et les fonctions 41


5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2 La fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3 Quelques Propriétés des fonctions sous C . . . . . . . . . . . . . . . . . . 44
5.3.1 Arguments muets et arguments effectifs . . . . . . . . . . . . . . . 44
5.3.2 L’instruction return . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.3.3 Cas des fonctions sans valeur de retour ou sans arguments . . . . 46
5.4 Déclarations des fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.4.1 Les différents façons de déclarer une fonction . . . . . . . . . . . . 47
5.4.2 A quel endroit on place la déclaration d’une fonction . . . . . . . 48
5.4.3 Pourquoi déclare−on une fonction . . . . . . . . . . . . . . . . . . 48
5.5 Réflexions sur les fichiers en−tête . . . . . . . . . . . . . . . . . . . . . . 49

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 2/77
5.6 Les arguments en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.7 Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.7.1 Exemple d’utilisation de variables globales . . . . . . . . . . . . . 51
5.7.2 La portée des variables globales . . . . . . . . . . . . . . . . . . . 52
5.7.3 La classe d’allocation des variables globales . . . . . . . . . . . . . 53
5.8 Les variables locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.8.1 La portée des variables locales . . . . . . . . . . . . . . . . . . . . 53
5.8.2 Les variables locales automatiques . . . . . . . . . . . . . . . . . . 54
5.8.3 Les variables locales statiques . . . . . . . . . . . . . . . . . . . . 54
5.8.4 Les fonctions récursive . . . . . . . . . . . . . . . . . . . . . . . . 55

6 Les tableaux 57
6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.2 Les tableaux à une dimension . . . . . . . . . . . . . . . . . . . . . . . . 58
6.2.1 Définitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
6.2.2 Déclaration et mémorisation . . . . . . . . . . . . . . . . . . . . . 58
6.2.3 Mémorisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3 Initialisation et réservation automatique . . . . . . . . . . . . . . . . . . 59
6.3.1 Initialisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3.2 Réservation automatique . . . . . . . . . . . . . . . . . . . . . . . 60
6.4 Accès aux composantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.4.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.4.2 Remarque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.5 Affichage et affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.6 Les tableaux à deux dimensions . . . . . . . . . . . . . . . . . . . . . . . 62
6.6.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.6.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.6.3 Déclaration et mémorisation . . . . . . . . . . . . . . . . . . . . . 63
6.6.4 Initialisation et réservation automatique . . . . . . . . . . . . . . 64
6.6.5 accès aux composantes . . . . . . . . . . . . . . . . . . . . . . . . 66

7 Les pointeurs 67
7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2 Stockage des variables en mémoire . . . . . . . . . . . . . . . . . . . . . 68
7.3 Définition et déclaration d’un pointeur . . . . . . . . . . . . . . . . . . . 68
7.4 Opérateur d’adresse : & . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.5 opérateur d’indirection ; * . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.6 Mémoire et pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.6.1 Commentaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.6.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.7 Adressage des composantes d’un tableau . . . . . . . . . . . . . . . . . . 70
7.7.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.7.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 3/77
7.7.3 Formalisme tableau et formalisme pointeur . . . . . . . . . . . . . 72
BIBLIOGRAPHIE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 4/77
TABLE DES FIGURES

4.1 Code ASCII des caractères clavier . . . . . . . . . . . . . . . . . . . . . . 33

7.1 Etat de la mémoire : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

5
S. SAFI Cours : Programmation en Langage C Sept. 2025
Page 6/77
INTRODUCTION GÉNÉRALE

e C a été conçu en 1972 par Dennis Richie et Ken Thompson, chercheurs aux Bell
L Labs, afin de développer un système d’exploitation UNIX sur un DEC PDP11. En
1978, Brian Kernighan et Dennis Richie publient la définition classique du C dans le
livre The C Programming language [1]. Le C devenant de plus en plus populaire dans
les années 80, plusieurs groupes mirent sur le marché des compilateurs comportant des
extensions particulières. En 1983, l’ANSI (American National Standards Institute) décida
de normaliser le langage ; ce travail s’acheva en 1989 par la définition de la norme ANSI
C. Celleci fut reprise telle quelle par l’ISO (International Standards Organization) en
1990.
Entre les années 1980 et 2000, aucun langage de programmation n’a pu se vanter
d’une croissance en popularité comparable à celle de C et de son frère (extension du C)
C + +. Ce n’est que vers l’an 2000 où le langage C doit passer sa première place au
langage Java − l’un de ses petit−fils. Même en Juin 2016, C occupe toujours la seconde
place dans le classement de la popularité, entouré de Java, C + +, C# et PHP qui sont
tous en quelque sorte des dérivés de C. Le langage C trouve ses sources en 1972 dans
les ’Bell Laboratories’ : Pour développer une version portable du système d’exploitation
UNIX, Dennis M. Ritchie a conçu ce langage de programmation structuré, mais très
’près’ de la machine.
Le succès des années qui suivaient et le développement de compilateurs C par d’autres
maisons ont rendu nécessaire la définition d’un standard actualisé et plus précis. En 1983,
le ’American National Standards Institute’ (ANSI) chargeait une commission de mettre
au point ’une définition explicite et indépendante de la machine pour le langage C’, qui
devrait quand même conserver l’esprit du langage. Le résultat était le standard ANSI-C.
La seconde édition du livre ’The C Programming Language’, parue en 1988, respecte tout
à fait le standard ANSI-C et elle est devenue par la suite, la référence des programmeurs
en C.
En 1983 un groupe de développeurs de AT &T sous la direction de Bjarne Stroustrup
a créé le langage C ++. Le but était de développer un langage qui garderait les avantages
de ANSI−C (portabilité, efficience) et qui permettrait en plus la programmation orientée
objet. Depuis 1990 il existe une ébauche pour un standard ANSI−C + +. Entre−temps

7
AT &T a développé deux compilateurs C + + qui respectent les nouvelles déterminations
de ANSI et qui sont considérés comme des quasi-standards (AT &T − C + + Version 2.1
[1990] et AT &T − C + + Version 3.0 [1992]).
Le grand succès du langage C s’explique par les avantages suivants ; C est un langage :
1. universel : C n’est pas orienté vers un domaine d’applications spéciales, comme
par exemple FORTRAN (applications scientifiques et techniques) ou COBOL (ap-
plications commerciales ou traitant de grandes quantités de données).
2. compact : C est basé sur un noyau de fonctions et d’opérateurs limité, qui permet
la formulation d’expressions simples, mais efficaces.
3. moderne : C est un langage structuré, déclaratif et récursif ; il offre des structures
de contrôle et de déclaration comparables à celles des autres grands langages de
ce temps (FORTRAN, ALGOL68, PASCAL).
4. près de la machine : comme C a été développé en premier lieu pour programmer
le système d’exploitation UNIX, il offre des opérateurs qui sont très proches de
ceux du langage machine et des fonctions qui permettent un accès simple et direct
aux fonctions internes de l’ordinateur ([Link] : la gestion de la mémoire).
5. rapide : comme C permet d’utiliser des expressions et des opérateurs qui sont
très proches du langage machine, il est possible de développer des programmes
efficients et rapides.
6. indépendant de la machine : bien que C soit un langage près de la machine, il
peut être utilisé sur n’importe quel système en possession d’un compilateur C. Au
début C était surtout le langage des systèmes travaillant sous UNIX, aujourd’hui
C est devenu le langage de programmation standard dans le domaine des micro-
ordinateurs.
7. portable : en respectant le standard ANSI−C, il est possible d’utiliser le même
programme sur tout autre système (autre hardware, autre système d’exploitation),
simplement en le recompilant.
8. extensible : C ne se compose pas seulement des fonctions standard ; le langage
est animé par des bibliothèques de fonctions privées ou livrées par de nombreuses
maisons de développement.
Dans ce cours, nous aborderons les chapitres suivants :
1. Introduction.
2. Types de base, variables, constantes.
3. Opérateurs et expressions.
4. Les entrées sorties en C.
5. Les structures de contrôle.
6. Lecture et écriture des données
7. Les tableaux.
8. Les pointeurs.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 8/77
CHAPITRE 1
L’ENVIRONNEMENT ET LES BIBLIOTHÈQUES

Sommaire
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Programme C : Forme générale . . . . . . . . . . . . . . . . . 10
1.2.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Les types de base du langage C . . . . . . . . . . . . . . . . . 12
1.3.1 Les entiers : int . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.2 Les réels :float . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.3 Les caractère :char . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4 Commentaires, noms et constantes . . . . . . . . . . . . . . . 13
1.4.1 Les commentaires . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.2 les noms d’objets . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.3 les constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.5 Déclaration de variables . . . . . . . . . . . . . . . . . . . . . 14
1.5.1 Les tableaux statiques . . . . . . . . . . . . . . . . . . . . . . . 14
1.5.2 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6 Les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . 15
1.6.1 Exemple 1 : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6.2 Exemple 2 : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.1 Introduction
Le langage C a été développé par Kernighan et Ritchie pour écrire le système Unix
dans un langage portable. Il a été largement utilisé tant pour l’écriture du noyau que
pour les principaux outils du système [Rif93]. Le langage est très populaire à présent,
quoique ancien ; il est très bien décrit dans le livre de référence de Kernighan et Ritchie
[KR90].

9
1.2 Programme C : Forme générale
n programme source C se présente sous forme d’une collection d’objets externes
U (variables et fonctions), dont la définition est éventuellement donnée dans des
fichiers séparés [Rif93].
Tout programme C est composé d’un programme principal, c’est-à-dire d’une fonction
particulière qui porte toujours le nom main [Pon97]. Une variable est un objet manipulé
par le programme, qui possède un nom et un type. Le type définit l’ensemble des valeurs
possibles pour l’objet.
En C, tout module (sous-programme) porte le nom de fonction. Une fonction est un
sous-programme.
Il s’agit d’un mécanisme permettant de donner un nom à un bloc afin de pouvoir le
réutiliser en différents points du programme. Une fonction permet d’enfermer certains
traitements dans une "boîte noire", dont on peut ensuite se servir sans se soucier de la
manière dont elle a été programmée.
Toutes les fonctions, dont le programme principal, sont constituées d’un bloc. Un bloc est
une suite d’instructions à l’intérieur d’accolades "{}”.

1.2.1 Exemple
Prenons un exemple de programme écrit en langage C, ce programme calcule la
somme des entier de 1 à N, la valeur de N doit être saisie par l’utilisateur.
/* Inclusion des informations de la bibliothèque standard */
#include < stdio.h >
/****************************************************************/
/* programme principal */
/* Calcul de la somme des entiers de 1 à N */
/* N étant saisi par l’utilisateur */
/****************************************************************/
void main ()
{ /* DECLARATION DES VARIABLES */
/* compteur de boucle */
int iCompteur ;
/* Somme initialisée à 0 */
int iSomme = 0 ;
/* Borne de la somme */
int N ;
/* CORPS DU PROGRAMME PRINCIPAL */
/* Demande de saisie de la borne à l’utilisateur */
printf ("Valeur de la borne de la somme :") ;
/* Lecture de la valeur de la borne */
scanf ("/* Pour tous les entiers allant de 1 à la borne */
for (iCompteur=1 ;iCompteur<=N ;iCompteur++)

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 10/77
{
/* Ajout de l’entier courant à la somme */
iSomme += iCompteur ; /* ? iSomme=iSomme+iCompteur */
/* Le compteur iCompteur est incrémenté (voir corps du for)*/
}
/*Affichage de la somme */
printf ("Somme =
} /* fin du programme principal */

♣ Explication du programme :

— Un bloc commence par une accolade ouvrante { et se termine par une accolade
fermante }.
— Les commentaires se mettent entre /* et */. Les commentaires peuvent être
sur plusieurs lignes.
— void main() définit une fonction appelée main qui ne reçoit pas d’arguments.
C’est le nom du programme principal.
void signifie que la fonction ne retourne rien. On parle dans ce cas de procédure.
— En début de programme, les variables sont déclarées. int iCompteur ; signifie
que la variable iCompteur est de type entier (integer).
— Chaque instruction se termine par un point virgule ;
— Il faut initialiser ( action qui consiste à manipuler une variable pour la première
fois, pour lui donner une valeur). une variable, sinon l’ordinateur peut lui affecter
n’importe quelle valeur. Il n’y a pas d’initialisation par défaut. On peut initialiser
une variable lors de sa déclaration : int iSomme=0 ;
— printf (...) : le programme principal (fonction main) appelle la fonction printf,
de la bibliothèque stdio.h, pour afficher la séquence de caractères "Valeur de la
borne de la somme :".
— scanf(...) : le programme principal (fonction main) appelle la fonction scanf, de
la bibliothèque stdio.h, qui lit la valeur tapée au clavier par l’utilisateur. Cette
valeur est de type entier puisque le format de lecture est "%d" (digit). La valeur
est mise dans la variable N.
— for (...) est une boucle. Le programme qui suit immédiatement le for
(ici iSomme+=iCompteur) va être exécuté autant de fois qu’il y a de passages
dans la boucle.
A l’intérieur des parenthèses, il y a trois parties :
1- La première partie est l’initialisation : iCompteur=1. Elle s’effectue une seule
fois, avant l’entrée dans la boucle.
2- La deuxième partie est le test de la condition : iCompteur<=[Link] partie
contrôle le déroulement de la boucle. Cette condition est évaluée comme suit :
→ Si la condition est vraie, on exécute le corps de la boucle (iSomme+=iCompteur),
puis on passe à la phase d’incrémentation (iCompteur++).
→ Si la condition est fausse, la boucle se termine.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 11/77
3- La troisième phase est l’incrémentation : l’instruction iCompteur++ est équi-
valent à l’instruction iCompteur = iCompteur + 1. Après cette phase, la boucle
reprend en 2.
— printf ("Somme ...") est l’appel à la fonction de sortie avec mise en forme. Son
premier argument est une chaîne de caractères à afficher, dans laquelle chaque
% (ici un seul) indique l’endroit où l’un des arguments suivants (le deuxième,
troisième, etc.) doit se substituer, et sous quel format l’afficher.
\n est un caractère spécial (retour à la ligne).
Après avoir analysé cet exemple, passons aux types de base utilisés en C.

1.3 Les types de base du langage C


1.3.1 Les entiers : int
Le type entier (int) est Codé sur 2 octets en général, parfois 4, selon la plate-forme
utilisée (UNIX, DOS, Windows ..). Le nombre d’octets utilisés pour coder un entier peut
être un paramètre de compilation, selon la plate-forme utilisée.
• Leurs valeurs : de −32768 à 32767 sur 2 octets et de −2147483648 à 2147483647 sur 4
octets.
• Le mode d’affichage en langage C est : %d.
Les types dérivés du int sont :

— unsigned int ou unsigned : entier non signé. Valeur de 0 à 65535 (si sur 2 oc-
tets).Format d’affichage : %u
— long int ou long : entier sur 4 octets - Format d’affichage : %ld
— unsigned long int ou unsigned long : entier long positif- Format d’affichage : %lu.
Le mot clé unsigned permet de supprimer le bit de signe.
— short int ou short : 2 octets - Format d’affichage : %d (ou %hd)

1.3.2 Les réels :float


Il existe deux types de réels : float sur 4 octets et double sur 8 octets.
Leurs formats d’affichage est : %f. Remarque :
Les constantes numériques sont par défaut de type double.

1.3.3 Les caractère :char


Ce type char est codé sur 1 octet.
Leurs valeurs : -128 à 127 ou 0 à 255 pour unsigned char.
Leurs formats d’affichage : %c pour les caractères et %s pour les chaînes de caractères.
Remarques :

1. Les constantes de type caractère sont notées entre apostrophes,

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 12/77
2. Les constantes de type chaîne de caractères sont notées entre guillemets
3. Il n’existe pas en C de type chaîne de caractères.
4. On note les caractères spéciaux (non imprimables) en commençant par \.

Caractère spécial Correspondance


\0 caractère nul (nul)
\a cloche ou bip.
\b retour arrière (backspace).
\f saut de page (form feed)
\n saut de ligne (line feed)
\r retour chariot (carriage return)
\t tabulation horizontale (horizontal tab)
\v tabulation verticale (vertical tab)
\\ \
\’ ’apostrophe
\" " guillemets
En langage C, il est important de bien comprendre les règles de conversions implicites
dans l’évaluation des expressions. Par exemple, si f est réel, et si i est entier, l’expression
f + i est autorisée et s’obtient par la conversion implicite de i vers un float [CL97].

1.4 Commentaires, noms et constantes


1.4.1 Les commentaires
En C, il est possible d’insérer un commentaire partout où l’insertion d’un espace est
possible. Un commentaire commence par une barre oblique suivie d’une étoile ( /* ), et
se termine par une étoile suivie d’une barre oblique ( */ ). Tout ce qui est compris entre
le deux est totalement ignoré par le compilateur.

Exemples
/* Ceci est un commentaire */
/* En voici un autre qui s’etend sur deux...
.... lignes */

1.4.2 les noms d’objets


En langage C (comme dans beaucoup d’autres langages), on désigne les objets que
l’on manipule par un nom. Pour être valide, le premier caractère d’un nom doit obliga-
toirement être une lettre (A...Z, a...z) ou un underscore (_). Les caractères suivants sont
choisis parmi les lettres (A...Z, a...z), les chiffres (0...9) ou l’underscore (_).

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 13/77
La norme ANSI n’impose aucune limite sur la longueur d’un nom. Il se peut que cer-
tains vieux compilateurs (ne respectant pas la norme) imposent une limite. Cette limite
n’est jamais inférieure à 8 caractères. Si cette limite existe, les caractères la dépassant
ne sont pas pris en compte pour distinguer deux noms.

1.4.3 les constantes


On distingue quatre types de constantes : entières, flottantes, caractères et chaînes.
Nous allons décrire ces différents type de constantes en se référant au type de variables
qui pourront les contenir. Ces types de variables sont décrits dans le chapitre concernant
les variables.

les constantes entières


Les constantes entières sont représentées par une suite de chiffres (en décimal par
défaut) précédée éventuellement par un signe (+ ou - ). Si cette suite commence par
0, la constante s’exprime en octal (base 8). Si cette suite commence par 0x ou 0X, la
constante s’exprime en héxadécimal (base 16). Par défaut, une constante entière est de
type int. Si la constante se termine par l ou L, elle est de type long. Si, elle se termine
par u ou U, elle est de type unsigned.

Constante Valeur décimale Type


1924 1924 int
0110 96(= 82 + 81 ) int
0xFF 255(= 15.161 + 15) int
-123L −123 long

les constantes chaînes


Les constantes chaînes de caractères s’écrivent entre des guillemets ("). Elles sont
constituées d’une suite de caractères. Comme pour les constantes caractères, on peut
utiliser le caractère d’échappement pour saisir des caractères spéciaux. Le compilateur
ajoute tout seul le caractère NUL (\0) en fin de chaîne. Une chaîne est de type pointeur
sur caractère (char *) et pointe sur un tableau de caractères contenant la suite des
caractères complétée par le caractère NUL de fin de chaîne (\0).
Exemple :
"Voici une chaîne terminée par une fin de ligne \n"

1.5 Déclaration de variables


1.5.1 Les tableaux statiques
Il s’agit de variables (caractères, entiers, réels, etc.) stockées consécutivement dans
la mémoire et que l’on peut manipuler globalement ou bien élément par élément. Les

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 14/77
tableaux statiques sont représentés par des crochets, entre lesquels est indiquée la taille
du tableau.

1.5.2 Exemples

Nous présentons les types principaux de déclaration des tableau en langage c.


Exemple 1 :
Déclaration : int iTableau[10] ; c’est un tableau de 10 entiers, iTableau est un pointeur,
c’est-à-dire l’adresse de début d’une zone mémoire de taille (nombre d’octets) égale au
nombre entre crochets multiplié par la taille du type du pointeur, soit 10 ∗ 2 octets.
Pour accéder au xieme élément du tableau iTableau, il faut faire : iTableau[x-1].
ATTENTION : Les éléments des tableaux sont indicés de 0 à n − 1.
Exemple 2 :
int iTabDeuxDim[5][4] ; c’est un tableau d’entiers à deux dimensions de 20 éléments.
iTabDeuxDim est un pointeur sur une zone de 4 ∗ 5 ∗ 2 octets.
Exemple 3 :
On peut remplir un tableau lors de sa déclaration :
int iTableau[] = 4,5,8,12,-3 ; c’est une déclaration et initialisation d’un tableau (on peut
mettre le nombre d’éléments à l’intérieur des crochets, mais dans ce cas, ce n’est pas obli-
gatoire). La taille du tableau est fixée à 5 éléments.

1.6 Les chaînes de caractères


Les chaînes de caractères sont représentées par des tableaux statiques ou par des
pointeurs.

1.6.1 Exemple 1 :

Déclaration : char cTabStatique[dimension] ;


cTabStatique est un identificateur dont le contenu est une adresse mémoire, à partir
de laquelle on peut réserver un nombre d’octets égal à la taille en octets d’un char mul-
tiplié par le nombre de caractères de la chaîne, c’est-à-dire un pointeur sur une zone de
caractères de taille dimension*taille_en_octets(char). Comme pour les tableaux
numériques, on peut initialiser un tableau de caractères (ou chaîne de caractères) lors de
sa déclaration :
♣ : char t[] = ”abcde”
♣ : char t[] = ’a’,’b’,...

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 15/77
1.6.2 Exemple 2 :
Déclaration : char* cPointeur ; cPointeur est un pointeur vers des caractères dont
la définition est dynamique. Il n’y a pas de réservation mémoire à la déclaration.
Pour mettre des caractères dans la valeur de cPointeur, il faut une allocation mémoire :
cPointeur = (char*) malloc (x)
- Cette fonction retourne un pointeur, x est le nombre d’octets à allouer.
- (char*) est un cast, c’est-à-dire un opérateur de conversion. Le pointeur retourné va
être converti en un pointeur de type pointeur sur un caractère.
Pour libérer la zone mémoire allouée : free (cPointeur) ;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 16/77
CHAPITRE 2

OPÉRATEURS ET EXPRESSIONS

Sommaire
2.1 les opérateurs arithmétiques . . . . . . . . . . . . . . . . . . . 18
2.2 les opérateurs incrémentaux . . . . . . . . . . . . . . . . . . . 19
2.3 les opérateurs bit à bit . . . . . . . . . . . . . . . . . . . . . . 20
2.4 Les opérateurs de décalage . . . . . . . . . . . . . . . . . . . . 20
2.5 les opérateurs de comparaison . . . . . . . . . . . . . . . . . . 21
2.6 les opérateurs logiques . . . . . . . . . . . . . . . . . . . . . . 21
2.7 les opérateurs d’affectation . . . . . . . . . . . . . . . . . . . . 21
2.8 l’opérateur conditionnel . . . . . . . . . . . . . . . . . . . . . 22
2.9 les opérateurs sur les pointeurs, tableaux et structures . . . 22
2.10 conversions de type . . . . . . . . . . . . . . . . . . . . . . . . 22
2.10.1 conversions implicites . . . . . . . . . . . . . . . . . . . . . . . 23
2.10.2 conversions explicites . . . . . . . . . . . . . . . . . . . . . . . . 23
2.11 conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

Introduction
Le langage C intègre de nombreux opérateurs. Certains sont des opérateurs unaires :
ils agissent sur un seul argument. D’autres sont des opérateurs binaires : ils combinent
deux arguments. Il existe même un opérateur ternaire agissant sur trois arguments.

17
Opérateurs Evaluation
() [] - > . →
! ++ – + - * & sizeof ←
*/+- →
«» →
< <= > >= →
== != →
& →
∧ →
| →
&& →
|| →
?: ←
= += -= *= /= , →

Dans une expression, la priorité entre les opérateurs est définie par la norme ANSI. Le
tableau (2 ci-dessus donne à titre indicatif tous les opérateurs classés par ordre croissant
de priorité et en spécifiant, pour chaque groupe d’opérateurs de priorité égale, le sens
d’évaluation. Un opérateur unaire est toujours plus prioritaire que le même opérateur
binaire : par exemple, l’opérateur - unaire (opposé) est prioritaire sur l’opérateur - binaire
(soustraction).
Le sens d’évaluation spécifie dans quel ordre sont évaluées des expressions de même
niveau de priorité. Par exemple, l’expression :
a = b − c − d;
est équivalent à écrire :
a = (b − c) − d; puisque l’opérateur - (binaire) est évalué de gauche à droite.
En revanche, l’expression :
a− = b− = c;
est équivalente à :
a− = (b− = c);
puisque l’opérateur − = est évalué de droite à gauche.
Remarque très important :
À tout programmeur (quel que soit son niveau), il est fortement conseillé d’utiliser les
parenthèses pour gérer explicitement l’ordre d’utilisation des opérateurs plutôt que de se
fier à sa connaissance de ce tableau de priorité. Cela évite de se tromper et rend surtout
le programme plus lisible.

2.1 les opérateurs arithmétiques


Il existe 7 opérateurs arithmétiques. Ils sont donnés dans le tableau 2.1.
Ces opérateurs font le calcul demandé et le type de la valeur produite dépend de celui
(ou ceux) de l’opérande (ou des opérandes). Par exemple, la résultat d’une division sera
de type int si ses deux opérandes sont eux-mêmes de type int. Par contre, si au moins un

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 18/77
Opérateurs Signification
+ (unaire) identité
- (unaire) opposé
+ (binaire) addition
-(binaire) soustraction
*(binaire) multiplication
÷(binaire) division
% (binaire) modulo

Table 2.1 – Opérateurs arithmétiques

Opérateurs Signification
++(unaire) incrémenter
−−(unaire) décrémenter

Table 2.2 – Opérateurs incrémentaux

des deux opérandes est de type double alors le résultat sera de type double. La division
entre deux entiers est donc une division entière.
Dans l’exemple suivant, a vaut 12 et b vaut 14 :
int x = 14, a ;
double y = 14, b ;
a = (x/4) ∗ 4 ;
b = (y/4) ∗ 4 ;

2.2 les opérateurs incrémentaux


On peux appliquer à une variable des opérateurs d’incrémentation ou de décrémen-
tation (tableau 2.2). C’est une incrémentation (ou une décrémentation) d’une unité. Le
contenu de la variable est modifié par ces opérateurs. Ces opérateurs peuvent être placés
avant ou après le nom de la variable. Si ils sont placés avant, la variable est incrémentée
(ou décrémentée) avant l’utilisation de sa valeur. Si ils sont placées après, la variable est
incrémentée après l’utilisation de sa valeur.
Dans l’exemple suivant, x vaut 11 ainsi que n.
int x,n = 10 ;
x = + + n;
Dans l’exemple suivant, x vaut 10 et n vaut 11.
int x,n = 10 ;
x = n + +;
Remarque :
Il est conseillé de ne pas abuser de cette possibilité pour ne pas rendre les programmes

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 19/77
Opérateurs Signification
! (unaire) négation
& (binaire) et bit à bit
| (bianre) ou bit à bit
ˆ(binaire) ou exclusif bit à bit

Opérateurs Signification
« (binaire) décalage vers la gauche
» (binaire) décalage vers la droite

Table 2.3 – Opérateurs de décalage

incompréhensibles.

2.3 les opérateurs bit à bit


Les opérateurs bit à bit effectue une opération logique (et, ou, ou exclusif, négation)
sur chacun des bits (tableau 2.3).
On utilise souvent ces opérateurs pour masquer certain bits (en les mettant à zéro) ou
pour forcer leur valeur (en les mettant à 1).

Dans l’exemple suivant, seuls le troisième bit et le quatrième bit de n conservent leur
valeur. Tous les autres sont mis à zéro ( 12 = 8 + 4 = 23 + 22 ).

n = n&12 ;
Ces opérateurs ne s’appliquent que sur des valeurs entières.

2.4 Les opérateurs de décalage


En C, il existe deux opérateurs de décalage (tableau 2.4). Ces deux opérateurs dé-
calent les bits composant une valeur vers la gauche ou vers la droite.
Le premier argument est la valeur à décaler tandis que le second argument est le nombre
de décalage à effectuer. Les bits qui sortent de la valeur sont perdus. Les nouveaux bits
sont mis à zéro. Un décalage à gauche d’un bit correspond à une multiplication par deux.
Alors qu’un décalage à droite d’un bit correspond à une division entière par deux. Dans
l’exemple suivant, on décale la valeur de n de 2 bits vers la droite :
n = n >> 2;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 20/77
Opérateurs Signification
< (binaire) strictement inférieur à
<= (binaire) inférieur ou égal à
> (binaire) strictement supérieur à
>= (binaire) supérieur ou égal à
== (binaire) égale à
!= (binaire) différent de

Table 2.4 – Opérateurs de comparaison

Opérateurs Signification
&& (binaire) et logique
k (binaire) ou logique
! négation logique

Table 2.5 – Opérateurs logiques

2.5 les opérateurs de comparaison


Il est possible de comparer les valeurs de deux expressions grâce à 6 opérateurs de
comparaison (tableau 2.5). Par convention, le résultat de ces opérateurs est 1 (vrai) ou
0 (faux). Par exemple, dans le programme suivant, x vaut 1.
int x = (3 ∗ 4) < (4 ∗ 5) ;

2.6 les opérateurs logiques


Les opérations logique (tableau 2.6) considèrent un opérande comme faux si sa valeur
est 0 et vrai dans tous les autres cas.
Par convention, le résultat de ces opérateurs est 1 (vrai) ou 0 (faux). Par exemple, dans
le programme suivant, x vaut 1 et y vaut 0 :
int n = 0, m = 10, x, y ;
x = (n < 20)&&m ;
y =!((n > 20)k(m == 10)) ;

2.7 les opérateurs d’affectation


Nous avons déjà dit qu’on utilisait l’opérateur = pour affecter le résultat d’une expres-
sion à une variable. Il est possible de préfixer l’opérateur = par la plupart des opérateurs
binaires. On obtient ainsi un nouvel opérateur d’affectation qui effectuera d’abord le
calcul entre l’expression et la valeur actuelle de la variable puis affectera le résultat à la

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 21/77
Opérateurs Signification
[] (binaire) accès à un élément d’un tableau
& (unaire) adresse de
* (unaire) contenu de
-> (binaire) accès à un champs pointé par
. (binaire) accès à un champs

Table 2.6 – Opérateurs sur les pointeurs, tableaux et structures

variable.
Les deux lignes, en C, suivantes sont donc équivalentes :
a∗ = b + 10;
a = a ∗ (b + 10);
Le résultat d’une affectation est la nouvelle valeur de la variable et il peut être utilisé
dans une autre expression. Dans l’exemple suivant a vaut 10 et b vaut 20 :
b = 2 ∗ (a = 10);

2.8 l’opérateur conditionnel


Il existe un seul opérateur ternaire en C. Cet opérateur permet d’écrire des expres-
sions conditionnelles. L’expression conditionnelle débute par un test suivi du caractère ?
puis la valeur lorsque le test est vrai puis le caractère : et enfin la valeur lorsque le test
est faux. y = 100;
a = (y < 200) ? 3.14 : 25 ;
b = (a > 3) ? ((y > 200)?10.1 : 5.0) : 123.0 ;

2.9 les opérateurs sur les pointeurs, tableaux et struc-


tures
Pour manipuler les tableaux, les structures, les pointeurs et la mémoire, il existe cinq
opérateurs (tableau 2.9). Nous en donnons la liste ici mais leur utilisation est plus dé-
taillée dans le chapitre consacré aux tableaux, pointeurs et structures.

2.10 conversions de type


Nous avons vu que, lors d’une division, les types des opérandes étaient importants
pour déterminer le type du résultat. Ceci est vrai pour toutes les opérations en C. Le C

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 22/77
effectue des conversions de type implicites lorsqu’elles sont nécessaires. On peut forcer
la conversion d’un type vers un autre grâce à l’opérateur de conversion explicite.

2.10.1 conversions implicites


Voici les règles simples permettant de déterminer les conversion implicites utilisées
en langage C. Ces règles sont appliquées dans l’ordre cité :

— Si l’un des opérandes est double, convertir l’autre en double.


— Si l’un des opérandes est float, convertir l’autre en float.
— Convertir les opérandes de type char et short en int.
— Si l’un des opérandes est long, convertir l’autre en long.
Lorsque la valeur d’une expression est un argument d’une fonction, la valeur est auto-
matiquement convertie vers le type de l’argument.

2.10.2 conversions explicites


Il est possible de spécifier une conversion explicitement (pour effectuer une division
entière entre deux double par exemple). Il suffit de précéder une expression par le nou-
veau type mis entre parenthèse. Dans l’exemple suivant, c vaut 3 (la division est une
division entière puisqu’on a converti explicitement les deux opérandes en int. Le résultat
est automatiquement converti en double puisque c est de type double) :
double a = 10, b = 3 ;
double c ;
c = ((int)a)/((int)b) ;

2.11 conclusion
Dans ce chapitre nous avons parcouru presque tous les opérateurs possible en langage
C, ainsi que leurs utilisation. Dans le chapitre suivant nous abordons les structures de
contrôles à savoir : les boucles et les tests.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 23/77
S. SAFI Cours : Programmation en Langage C Sept. 2025
Page 24/77
CHAPITRE 3
LES STRUCTURES DE CONTRÔLE : BOUCLES ET TESTS

Sommaire
3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2 Les structures de boucles . . . . . . . . . . . . . . . . . . . . . 25
3.2.1 Les structures while . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.2 Les structures for . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.3 les instructions de contrôles de boucles . . . . . . . . . . . . 28
3.3.1 les structures de choix . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.2 la structure de choix multiples . . . . . . . . . . . . . . . . . . 29
3.4 conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.1 Introduction
près avoir précisé la notion d’instruction, la notion de variable et l’affectation de
A valeurs aux variables, nous décrivons, dans ce chapitre, les différentes structures de
contrôle disponibles en langage C. Ces structures permettent de contrôler l’ordre dans
lequel seront effectuées les instructions.

3.2 Les structures de boucles


Avant de donner la description des boucles en langage C, nous présentons une re-
marque très importante sur l’utilisation des pints-virgules et des accolades.
Remarque :

1. Le caractère ; termine une instruction. N’importe quelle expression devient une


instruction simple dès qu’elle est suivie d’un point-virgule.

25
2. Les accolades permettent de regrouper une suite de plusieurs instructions (simples
ou composées) en une seule instruction composée (ou bloc).
3. Il est possible de déclarer ou de définir des variables au début de chaque bloc. Ces
variables n’existeront que dans ce bloc.
Exemple :
Dans cet exemple on présente trois instructions simples correctes qui sont réunies en une
instruction composée (ou bloc) :
{
a = 1;
x + +;
f (x) ;
}

3.2.1 Les structures while


En langage C, Il y a deux utilisations possibles du while.
La première utilisation évalue une condition puis exécute l’instruction (simple ou com-
posée) qui suit si la condition est vraie. Cette boucle continue tant que la condition reste
vraie. Le premier exemple l’illustre avec une instruction simple tandis que le second uti-
lise une instruction composée.
while (condition)
instruction ;
while (condition)
{
instruction 1 ;
...
instruction n ;
}

La seconde utilisation exécute tout d’abord l’instruction (simple ou composée). Puis


la condition est évaluée et, tant qu’elle reste vraie, l’instruction est exécutée à nouveau.
Les deux exemples suivants l’illustrent avec une instruction simple :
do
instruction
while (condition) ;
et une instruction composée :
do
{
instruction 1 ;
...
instruction n ;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 26/77
} while (condition) ;

3.2.2 Les structures for


Le mot-clé for permet lui aussi d’effectuer des boucles. Il pourrait ne pas exister puis-
qu’on peut le simuler avec while. Ainsi :
for (expr1 ; expr2 ; expr3) {
instruction 1 ;
...
instruction n ;
}
est équivalent à :
expr1 ; while (expr2)
{
instruction 1 ;
...
instruction n ;
expr3 ;
}
La première expression expr1 est l’expression d’initialisation. La seconde expression
expr2 est le test de continuation. La troisième expression expr3 est appelée expression
d’incrémentation.
Dans l’exemple suivant, nous représentons l’utilisation de la boucle for dans un tableau :
int Tab[10], i ;

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


{
/* manipulation du ieme element */ Tab[i] = ...
...
}
Remarque :
Dans un for , chacune des trois expressions peut-être absente par contre il faut conser-
ver les points-virgules. Si une expression n’est pas présente tout se passe comme si elle
n’existait pas (en particulier, la seconde expression est considérée comme vraie si elle
n’existe pas). On peut donc écrire une boucle infinie de la manière suivante :
for ( ; ;)
{
instruction 1 ;
...
instruction n ;
}

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 27/77
3.3 les instructions de contrôles de boucles
Il existe deux instructions particulières pour contrôler l’exécution d’une boucle.
L’instruction break permet de quitter immédiatement l’exécution d’une boucle (par
exemple une boucle infinie).
L’instruction continue permet de passer immédiatement au test suivant (sauf dans le
cas du for où l’expression expr3 est tout de même évaluée).
L’utilisation des ces deux instructions dans le cadre d’une programmation structurée
est déconseillée sauf lorsque cela augmente la lisibilité du programme.

3.3.1 les structures de choix


la structures if

Le mot-clé if permet d’effectuer une instruction (simple ou composée) de manière


conditionnelle. Il peut être suivi du mot-clé else pour spécifier l’instruction à effectuer
lorsque la condition est fausse.

if sans else

if (condition)
{
/* si la condition est vraie */
instruction 1 ;
...
instruction n ;
}

if- else

if (condition)
/* si la condition est vraie */
instruction 1 ;
... ;
instruction n ;
else
/* si la condition est fausse */
instruction 1 ;
...
instruction n ;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 28/77
if -else if-...- else

Il est possible d’enchaîner plusieurs tests successifs grâce à else if :


if (condition1)
{ /* si condition1 est vraie */
instruction ;
else if (condition2)
{ /* si condition1 est fausse et condition2 est vraie */
instruction ;
else
/* si les deux conditions sont fausses */
instruction
}}

3.3.2 la structure de choix multiples


Le mot-clé switch permet d’effectuer un choix selon les valeurs possibles d’une ex-
pression. On sélectionne une valeur particulière en la faisant précéder du mot-clé case
. Le mot-clé default permet de spécifier le comportement par défaut (c’est à dire lors-
qu’aucune des valeurs spécifiées n’est la bonne).
switch (expression)
{
case Constante1 :
/* si expression est égale a Constante1 */
instruction 1 ;
...
instruction n ;
break ;
case Constante2 :
/* si expression est égale a Constante2 */
instruction 1 ;
...
instruction n ;
break ;
...
default :
/* cas par defaut */
instruction 1 ;
...
instruction n ;
break ;
}
Attention :

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 29/77
n’oubliez pas le break entre chaque cas sinon l’exécution continue sur le cas suivant. Ceci
permet de spécifier plusieurs valeurs pour une même série d’instructions.
Dans l’exemple suivant, les valeurs 1, 2 et 3 déclenchent le même traitement. La valeur
4 est traitée séparément :
switch (a)
case 1 :
case 2 :
case 3 :
b = 100 ;
break ;
case 4 :
b = 200 ;
break ;
default :
b = 0;
break ;

3.4 conclusion
Dans ce chapitre nous avons présenté les structures de contrôle qui définissent la suite
dans laquelle les instructions sont effectuées. Dans ce chapitre, nous avons vu comment
fonctionnent en langage C, les structures alternatives qui nous permet de choisir entre
plusieurs instructions suivant un test logique ’vrai’ ou ’faut’.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 30/77
CHAPITRE 4
LECTURE ET ÉCRITURE DES DONNÉES

Sommaire
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Écriture formatée de données . . . . . . . . . . . . . . . . . . 31
4.2.1 Exemple 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.2.2 Exemple 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.2.3 Arguments rationnels . . . . . . . . . . . . . . . . . . . . . . . 33
4.2.4 Arguments rationnels . . . . . . . . . . . . . . . . . . . . . . . 34
4.2.5 Largeur minimale pour les entiers . . . . . . . . . . . . . . . . . 35
4.2.6 Largeur minimale et précision pour les rationnels . . . . . . . . 35
4.3 Lecture formatée de données . . . . . . . . . . . . . . . . . . 36
4.3.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.4 Impression et lecture de caractères . . . . . . . . . . . . . . . 38
4.5 conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

4.1 Introduction
n le langage C, la bibliothèque standard < stdio > contient l’ensemble des fonctions
D qui assurent la communication entre la machine et le monde extérieur. Dans ce
chapitre, nous allons en discuter les fonctions les importantes à savoir : printf() : écriture
formatée de données
scanf() : lecture formatée de données putchar() : écriture d’un caractère getchar() : lecture
d’un caractère

4.2 Écriture formatée de données


La fonction qui permet d’afficher des données sur l’écran de la machine (fonction
écrire en algorithmique), en langage C est la fonction printf(). Cette fonction est utili-

31
sée pour transférer du texte, des valeurs de variables ou des résultats d’expressions vers
le fichier de sortie standard stdout (par défaut l’écran).
La syntaxe en langage C est :
printf (” < f ormat > ”, < expr1 >, < expr1 >, ...)
"<format>" : format de représentation.
<Expr1>,... : variables et expressions dont les valeurs sont à représenter
La partie "<format>" est en fait une chaîne de caractères qui peut contenir :

1. du texte,
2. des séquences d’échappement,
3. des spécificateurs de format
4. Les spécificateurs de format indiquent la manière dont les valeurs des expressions
<Expr1..N> sont imprimées.
5. La partie "<format>" contient exactement un spécificateur de format pour chaque
expression <Expr1..N>.
6. Les spécificateurs de format commencent toujours par le symbole % et se ter-
minent par un ou deux caractères qui indiquent le format d’impression.
7. Les spécificateurs de format impliquent une conversion d’un nombre en chaîne de
caractères. Ils sont encore appelés symboles de conversion.

4.2.1 Exemple 1
La suite d’instructions :
int A = 234 ;
int B = 67 ;
printf("%i fois %i est %li\ n", A, B,(long)A*B) ;
va afficher sur l’écran :
234 fois 67 est 615678
Explication
Les arguments de printf sont :
- la partie format est : "%i fois %i est %li"
- la variable A
- la variable B
- l’expression (long)A ∗ B
Le 1er spécificateur (%i) indique que la valeur de A
sera imprimée comme entier relatif : 234
Le 2e me spécificateur (%i) indique que la valeur de B
sera imprimée comme entier relatif : 67
Le 3e me spécificateur (%li) indique que la valeur de (long)A ∗ B
sera imprimée comme entier relatif long : 615678

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 32/77
4.2.2 Exemple 2
Dans cet exemple, prenons la suite d’instructions : char B = ’A’ ;
printf("Le caractère %c a le code %i !\ n", B, B) ;
va afficher sur l’écran :
Le caractère A a le code 65 !
La valeur de B est donc affichée sous deux formats différents :
%c : comme caractère : A
%i : comme entier relatif : 65

Figure 4.1 – Code ASCII des caractères clavier

Dans le tableau (4.2.2) nous représentons les formats possible pour la fonction printf ().

4.2.3 Arguments rationnels


Les spécificateurs %d, %i, %u, %o, %x peuvent seulement représenter des valeurs du
type int ou unsigned int. Une valeur trop grande pour être codée dans deux octets est
coupée sans avertissement si nous utilisons %d.
Pour pouvoir traiter correctement les arguments du type long, il faut utiliser les spécifi-
cateurs %ld, %li, %lu, %lo, %lx.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 33/77
Symbole type impression comme
%d ou % int entier relatif
%u int entier naturel (unsigned)
%o int entier exprimé en octal
%x int entier exprimé en hexadécimal
%c int caractère
%f double rationnel en notation décimale
%e double rationnel en notation scientifique
%s char* chaîne de caractères

Exemple

Dans cet exemple nous donnons comment on peut utiliser une format long double
"%le".
long N = 1500000 ; printf ("%ld, %lx", N, N) ; le résultat sur l’écran d’affichage est :
1500000, 16e360
printf ("%x, %x" , N) ; le résultat sur l’écran d’affichage est : e360, 16
printf("%d, %d" , N) ; le résultat sur l’écran d’affichage est : -7328, 22

4.2.4 Arguments rationnels


Les spécificateurs %f et %e peuvent être utilisés pour représenter des arguments du
type float ou double. La mantisse des nombres représentés par %e contient exactement
un chiffre (non nul) devant le point décimal. Cette représentation s’appelle la notation
scientifique des rationnels.
Pour pouvoir traiter correctement les arguments du type long double, il faut utiliser les
spécificateurs %Lf et %Le.

Exemple

Dans cet exemple nous donnons comment on peut utiliser une format long double
"%le" et "%lf".
float N = 12.1234 ;
double M = 12.123456789 ;
long double P = 15.5 ;
printf("%f", N) ; donne comme résultat sur l’écran d’affichage : 12.123400
printf("%f", M) ; donne comme résultat sur l’écran d’affichage : 12.123457
printf("%e", N) ; donne comme résultat sur l’écran d’affichage : 1.212340e+01
printf("%e", M) ; donne comme résultat sur l’écran d’affichage : 1.212346e+01
printf("%Le", P) ; donne comme résultat sur l’écran d’affichage : 1.550000e+01

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 34/77
4.2.5 Largeur minimale pour les entiers
Pour les entiers, nous pouvons indiquer la largeur minimale de la valeur à afficher.
Dans le champ ainsi réservé, les nombres sont justifiés à droite.

Exemples

(_ : positioon libre)
printf("%4d", 123) ;
résultat affiché sur l’écran : _123
printf("%4d", 1234) ;
résultat affiché sur l’écran : 1234
printf("%4d", 12345) ;
résultat affiché sur l’écran : 12345
printf("%4u", 0) ;
résultat affiché sur l’écran :___0
printf("%4X", 123) ;
résultat affiché sur l’écran :__7B
printf("%4x", 123) ;
résultat affiché sur l’écran :__7b

4.2.6 Largeur minimale et précision pour les rationnels


Pour les rationnels, nous pouvons indiquer la largeur minimale de la valeur à afficher
et la précision du nombre à afficher. La précision par défaut est fixée à six décimales. Les
positions décimales sont arrondies à la valeur la plus proche.

Exemples

printf("%f", 100.123) ;
résultat affiché sur l’écran : 100.123000
printf("%12f", 100.123) ;
résultat affiché sur l’écran : __100.123000
printf("%.2f", 100.123) ;
résultat affiché sur l’écran : 100.12
printf("%5.0f", 100.123) ;
résultat affiché sur l’écran : __100
printf("%10.3f", 100.123) ;
résultat affiché sur l’écran : ___100.123
printf("%.4f", 1.23456) ;
résultat affiché sur l’écran : 1.2346

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 35/77
! !h
Symbole Lecture Type
%d ou %i entier relatif int*
%u entier naturel (unsigned) int*
%o entier exprimé en octal int*
%b entier exprimé en hexadécimal int*
%c caractères char*
%s chiane de caractère char*
%f ou %e rationnel en notation décimale ou exponentielle (scientifique) float*

4.3 Lecture formatée de données


La fonction scanf est la fonction symétrique à printf ; elle nous offre pratiquement les
mêmes conversions que printf, mais en sens inverse. C’est-à-dire si la fonction printf() écrit
(écriture en algorithmique) sur l’écran, la fonction scanf() lit (lecture en algorithmique)
les données.
La syntaxe de la fonction scanf () en langage C :
scanf ("<format>",<AdrVar1>,<AdrVar2>, ...)
"<format>" : format de lecture des données,
<AdrVar1>,... : adresses des variables auxquelles les données seront attribuées.
Donc on a :
• La fonction scanf reçoit ses données à partir du fichier d’entrée standard stdin (par
défaut le clavier).
• La chaîne de format détermine comment les données reçues doivent être interprétées. •
Les données reçues correctement sont mémorisées successivement aux adresses indiquées
par <AdrVar1>,...
Remarque : L’adresse d’une variable est indiquée par le nom de la variable précédé du
signe &.

4.3.1 Exemple
Examinons la suite d’instructions :
int JOUR, MOIS, ANNEE ;
scanf ("%i %i %i, &JOUR, &MOIS, &ANNEE) ;
La deuxième ligne lit trois entiers relatifs, séparés par des espaces, tabulations ou inter-
lignes. Les valeurs sont attribuées respectivement aux trois variables JOUR, MOIS et
ANNEE. La fonction scanf retourne comme résultat le nombre de données correctement
reçues (type int).
Dans le tableau (table 4.3.1) suivant nous les formats possible de la fonction scanf ().
Le symbole * indique que l’argument n’est pas une variable, mais l’adresse d’une va-
riable de ce type (c.-à-d. : un pointeur sur une variable - voir le chapitre consacré aux
pointeurs’).

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 36/77
— Le type long : Pour lire une donnée de type long, nous devons utiliser les spé-
cificateurs %ld,%li, %lu, %lo, %lx. (Sinon, le nombre est simplement coupé à la
taille de int).
— Le type double : Pour lire une donnée du type double, nous devons utiliser les
spécificateurs %le ou %lf.
— Le type long double : Pour lire une donnée du type long double, nous devons
utiliser les spécificateurs %Le ou %Lf.
— Indication de la largeur maximale : Pour tous les spécificateurs, nous pouvons
indiquer la largeur maximale du champ à évaluer pour une donnée. Les chiffres
qui passent au-delà du champ défini sont attribués à la prochaine variable qui sera
lue !
Exemple :
Considérons les instructions suivantes :
int A, B ;
scanf ("%4d %2d", &A, &B) ;
Si nous entrons le nombre 1234567, nous obtiendrons les affectations suivantes :
A=1234
B=56
Le chiffre 7 sera gardé pour la prochaine instruction de lecture.

— Les signes d’espacement : Lors de l’entrée des données, une suite de signes
d’espacement (espaces, tabulateurs, interlignes) est évaluée comme un seul es-
pace. Dans la chaîne de format, les symboles \t, \n,\r ont le même effet qu’un
simple espace.
Exemple :
Prenons la suite d’instructions suivante :
int JOUR, MOIS, ANNEE ;
scanf ("%i %i %i", &JOUR, &MOIS, &ANNEE) ;
les entrées suivantes sont correctes et équivalentes :
12 4 1980
ou
12 004 1980
ou
12
4
1980

— Format ’spéciaux’ : Si la chaîne de format contient aussi d’autres caractères


que des signes d’espacement, alors ces symboles doivent être introduits exacte-
ment dans l’ordre indiqué.
Exemple :
La suite d’instructions int JOUR, MOIS, ANNEE ; scanf ("%i/%i/%i", &JOUR,

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 37/77
&MOIS, &ANNEE) ; Dans cet exemple, les entrées acceptés sont :
17/7/1974 et 17/07/01974.
et les entrées non acceptées sont :
17 7 1974 et 17/4/1980.

— Nombre de valeurs lues : Lors de l’évaluation des données, scanf s’arrête si


la chaîne de format a été travaillée jusqu’à la fin ou si une donnée ne correspond
pas au format indiqué. scanf retourne comme résultat le nombre d’arguments
correctement reçus et affectés.
Exemple :
Lorsqu’on exécute la suite d’instruction suivante :
int JOUR, MOIS, ANNEE, RECU ;
RECU = scanf("%i %i %i", &JOUR, &MOIS, &ANNEE) ;
nous obtenons quelques valeurs indéfini lorsqu’on introduit les valeurs (tableau
4.3.1) suivantes :

introduit (tapper au clavier) RECU JOUR MOIS ANNEE


17 7 1974 3 17 7 1974
17/7/1974 1 17 - -
17. 7 1974 1 17 - -
17 7 19.74 3 17 4 19

4.4 Impression et lecture de caractères


Les fonctions getchar et putchar permettent respectivement de lire et d’imprimer
des caractères. Il s’agit de fonctions d’entrées-sorties non formatées.
La fonction getchar retourne un int correspondant au caractère lu.
Pour mettre le caractère lu dans une variable caractere, on écrit caractere = getchar() ;
Lorsqu’elle détecte la fin de fichier, elle retourne l’entier EOF (End Of File), valeur dé-
finie dans la librairie stdio.h. En général, la constante EOF vaut -1.
La fonction putchar écrit caractere sur la sortie standard : putchar(caractere) ;
Elle retourne un int correspondant à l’entier lu ou à la constante EOF en cas d’erreur.
Par exemple, le programme suivant lit un fichier et le recopie caractère par caractère à
l’écran.
#include <stdio.h>
main()

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

Notons que l’expression (c = getchar()) dans le programme précédent a pour valeur


la valeur de l’expression getchar() qui est de type int. Le test (c = getchar()) != EOF

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 38/77
compare donc bien deux objets de type int (signés).
Ce n’est par contre pas le cas dans le programme suivant :
#include <stdio.h>
main()

char c ;
do

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

while (c != EOF) ;
Ici, le test c != EOF compare un objet de type char et la constante EOF qui vaut -1.
Si le type char est non signé par défaut, cette condition est donc toujours vérifiée.
Si le type char est signé, alors le caractère de code 255, y, sera converti en l’entier -1.
La rencontre du caractère y sera donc interprétée comme une fin de fichier.
Il est donc recommandé de déclarer de type int (et non char) une variable destinée à
recevoir un caractère lu par getchar afin de permettre la détection de fin de fichier.
Une fonction plus souvent utilisée que putchar est la fonction getchar, qui lit le prochain
caractère du fichier d’entrée standard stdin.
Les valeurs retournées par getchar sont ou bien des caractères (0 - 255) ou bien le sym-
bole EOF. Comme la valeur du symbole EOF sort du domaine des caractères, le type
résultat de getchar est int. En général, getchar est utilisé dans une affectation :

int C ;
C = getchar() ;
getchar lit les données de la zone tampon de stdin et fournit les données seulement après
confirmation par ’Enter’.
La bibliothèque <conio> contient une fonction du nom getch qui fournit immédiate-
ment le prochain caractère entré au clavier. Remarque :
La fonction getch n’est pas compatible avec ANSI-C et elle peut seulement être utilisée
sous MS-DOS.

4.5 conclusion
Dans ce chapitre nous avons présenté les principaux fonctions qui assurent l’interface
homme-machine, à savoir : les fonctions de lecture est d’écriture. A cet effet nous avons
la fonction printf() qui assure l’écriture formatée des données, la fonction scanf() qui qui
sert à lire les données formatées entrée au clavier ainsi que les fonctions putchar() et
getchar() qui permettent l’écriture et la lecture d’un caractère.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 39/77
S. SAFI Cours : Programmation en Langage C Sept. 2025
Page 40/77
CHAPITRE 5
LA PROGRAMMATION MODULAIRE ET LES
FONCTIONS

Sommaire
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2 La fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3 Quelques Propriétés des fonctions sous C . . . . . . . . . . . 44
5.3.1 Arguments muets et arguments effectifs . . . . . . . . . . . . . 44
5.3.2 L’instruction return . . . . . . . . . . . . . . . . . . . . . . . . 45
5.3.3 Cas des fonctions sans valeur de retour ou sans arguments . . . 46
5.4 Déclarations des fonctions . . . . . . . . . . . . . . . . . . . . 47
5.4.1 Les différents façons de déclarer une fonction . . . . . . . . . . 47
5.4.2 A quel endroit on place la déclaration d’une fonction . . . . . . 48
5.4.3 Pourquoi déclare−on une fonction . . . . . . . . . . . . . . . . 48
5.5 Réflexions sur les fichiers en−tête . . . . . . . . . . . . . . . 49
5.6 Les arguments en C . . . . . . . . . . . . . . . . . . . . . . . . 50
5.7 Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.7.1 Exemple d’utilisation de variables globales . . . . . . . . . . . . 51
5.7.2 La portée des variables globales . . . . . . . . . . . . . . . . . . 52
5.7.3 La classe d’allocation des variables globales . . . . . . . . . . . 53
5.8 Les variables locales . . . . . . . . . . . . . . . . . . . . . . . . 53
5.8.1 La portée des variables locales . . . . . . . . . . . . . . . . . . 53
5.8.2 Les variables locales automatiques . . . . . . . . . . . . . . . . 54
5.8.3 Les variables locales statiques . . . . . . . . . . . . . . . . . . . 54
5.8.4 Les fonctions récursive . . . . . . . . . . . . . . . . . . . . . . . 55

41
5.1 Introduction
l est très intéressant de découper un programme en plusieurs parties appelés géné-
I ralement "modules". d’ou la nomination de programmation modulaires. On peut
citer quelques avantages de la programmation modulaires comme suit :

— Rendre le programme plus lisible et plus simple à analyser et à corriger,


— Lorsque le programme une ou deux pages, 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. Comme on peut décomposer chacune
de ces parties, ce processus de décomposition pouvant être répété autant de fois
que nécessaire : 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.

5.2 La fonction
A noter que les fonctions représentent la seule sorte de module existant dans C. Dans
C, une fonction peut prendre des aspects différents :

— La valeur d’une fonction pourra très ne pas utilisée ; c’est ce qui se passe fréquem-
ment lorsqu’on utilise les fonctions printf ou scanf. A noter, que cela n’a d’intérêt
que parce que de telles fonctions réalisent une action (ce qui, dans autres langages,
serait réservé aux sous programmes ou procédures).
— Une fonction pourra ne fournir aucune valeur.
— Une fonction pourra fournir un résultat non scalaire (voir plus loin chapitre consa-
cré aux structures).
— Une fonction pourra modifier les valeurs de certains de ses arguments (voir cha-
pitre sur les pointeurs).
Nous verrons qu’on C plusieurs fonctions peuvent partager des informations, autrement
que par ’passage d’arguments’. Nous retrouvant la notion classique de ’variables globales’
(en Basic et Fortran, toutes les variables sont globales).
Parmi les avantages du langage C réside dans la possibilité de ’compilation séparé’. Celle-
ci permet de découper le programme source en plusieurs parties, chacune de ces parties
pouvant comporter une ou plusieurs fonctions 1

1. Certains auteurs emploient parfois le mot ’module’ pour désigner chacune de ces parties (stockées
dans un fichier) ; dans ce cas, le terme de module devient synonyme de fichier source.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 42/77
Cela facilite considérablement le développement et la mise au point de grosses appli-
cations. Cette possibilité crée naturellement quelques contraintes supplémentaires, no-
tamment au niveau des variables globales que l’on souhaite partager entre différentes
parties du programme source (c’est d’ailleurs ce qui justifiera l’existence de la déclara-
tion extern).
Pour garder une certaine progressivité dans notre exposé, nous supposerons tout d’abord
que nous avons affaire à un programme source d’un seul tenant (ce qui ne nécessite donc
pas de compilation séparée). Nous présenterons ainsi la structure générale d’une fonction,
les notions d’arguments, de variables globales et locales. Ce n’est qu’alors que nous in-
troduirons les possibilités de compilation séparée en montrant quelles sont ses incidences
sur les points précédents ; cela nous amènera à parler des différentes "classes d’allocation"
des variables.

5.2.1 Exemple
Nous vous proposons d’examiner tout d’abord un exemple simple de fonction corres-
pondant à 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 fct (float, int, int) ; /* déclaration de fonction fct */
float x = 1.5 ;
float y, z ;
int n = 3, p = 5, q = 10 ;
/* appel de fct avec les arguments x, n et p */
y = f exple(x, n, p) ;
printf ("valeur de y : %e\n", y) ;
/* appel de fct 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 fct ****************/
float fct(float x, int b, int c)
{
float val ; /* déclaration d’une variable "locale" à fct
val = x ∗ x + b ∗ x + c ;
return val ;
}
Donc, Nous y trouvons tout d’abord, un programme principal formé d’un bloc, par la
suite, nous avons la définition d’une fonction : sa structure est voisine de la fonction
main, à savoir un en-tête et un corps délimité par des accolades ( et ).

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 43/77
L’en-tête est plus élaboré que celui de la fonction main puisque, plus que le nom de
la fonction (fct), on y trouve une liste d’arguments (nom + type) et le type de la
valeur qui sera fournie par la fonction (résultat de retour ...) :
float fct (float x, int b, int c)
— Type de la valeur retournée par la fonction,
— Nom de la fonction,
— Types et noms des arguments de la fonction.
Remarque :
Les noms des arguments n’ont d’importance qu’au sein du corps de la fonction. Ils servent
à décrire le travail que devra effectuer la fonction quand on l’appellera en lui fournissant
trois valeurs.
Dans le corps de la fonction nous trouvons l’instruction suivante : float val ;
Ca veux dire que la fonction fct à besoin d’une variable de type float pour fonctionner,
dans ce cas on dit que val est variable locale à la fonction fct, de même que les va-
riables n, p, y... sont des variables locales à la fonction main.
A noter que l’instruction return val précise la valeur que fournira la fonction à la fin de
son travail, on peut dire que fct est une fonction telle que fct (x, b, c) fournisse la valeur
de l’expression x2 + bx + c.
float fct (float z, int c, int n)
{
float val ; /* déclaration d’une variable "locale" à fct */
val = z ∗ z + c ∗ z + n ;
return val ;
}
La déclaration suivante, dans la fonction main(), sert à prévenir le compilateur que fct
est une fonction et elle lui précise le type de ses arguments ainsi que celui de sa valeur
de retour.
float fct (float, int, int)

5.3 Quelques Propriétés des fonctions sous C


5.3.1 Arguments muets et arguments effectifs
Les noms des arguments figurant dans l’en-tête de la fonction se nomment des ar-
guments muets, ou encore arguments formels ou paramètres formels (formal para-
meter). Leur rôle est de permettre, au sein du corps de la fonction, de décrire ce qu’elle
doit faire.
Les arguments fournis lors de l’utilisation (l’appel) de la fonction se nomment des ar-
guments effectifs (ou paramètres effectifs). Dans l’exemple précédent, on peut utiliser
n’importe quelle expression comme argument effectif ; mais en fin, c’est la valeur de cette
expression qui sera transmise à la fonction lors de son appel.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 44/77
Notez qu’il serait impossible d’écrire un en-tête de fct sous la forme float fct (float
a + b, ...), il est bien clair qu’en mathématiques vous ne définiriez une fonction f par
f (x + y) = 5 !

5.3.2 L’instruction return


L’instruction return peut mentionner n’importe quelle expression. Donc, on peut dé-
finir la fonction fct précédente d’une manière plus simple :
float fct (float x, int b, int c)
{
return (x * x + b * x + c) ;
}
L’instruction return peut apparaître à plusieurs reprises dans une fonction, comme dans
l’exemple suivant :
double absom (double u, double v)
{
double s ;
s = a + b;
if (s > 0)
return (s) ;
else
return (−s)
}
Remarque :
Notez bien que non seulement l’instruction return définit la valeur du résultat, mais, en
même temps, elle interrompt l’exécution de la fonction en revenant dans la fonction qui
l’a appelée (n’oubliez pas qu’en C tous les modules sont des fonctions, y compris le pro-
gramme principal).
Nous verrons qu’une fonction peut ne fournir aucune valeur : elle peut alors disposer de
une ou plusieurs instructions return sans expression, interrompant simplement l’execu-
tion de la fonction ; mais elle peut aussi dans ce cas ne comporter aucune instruction
return, le retour étant alors mis en place automatiquement par le compilateur à la fin de
la fonction.
Si le type de l’expression figurant dans return est différent du type du résultat tel qu’il a
été déclaré dans l’en-tête, le compilateur mettra automatiquement en place des instruc-
tions de conversion.
Il est toujours possible de ne pas utiliser le résultat d’une fonction, même si elle en pro-
duit un. C’est d’ailleurs ce que nous avons fait fréquemment avec printf ou scanf.
Bien entendu, cela n’a d’intérêt que si la fonction fait autre chose que de calculer un
résultat. En revanche, il est interdit d’utiliser la valeur d’une fonction ne fournissant pas
de résultat (si certains compilateurs l’acceptent, vous obtiendrez, lors de l’exécution, une
valeur aléatoire !).

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 45/77
5.3.3 Cas des fonctions sans valeur de retour ou sans arguments

Quand une fonction ne renvoie pas de résultat, on le précise, à la fois dans l’en-tête et
dans sa déclaration, à l’aide du mot-clé void. Par exemple, voici l’en-tête d’une fonction
recevant un argument de type int et ne fournissant aucune valeur :
void sansval (int n)
et voici quelle serait sa déclaration :
void sansval (int) ;
Naturellement, la définition d’une telle fonction ne doit, en principe, contenir aucune
instruction return. Certains compilateurs ne détecteront toutefois pas l’erreur.
Quand une fonction ne reçoit aucun argument, on place le mot-clé void (le même que
précédemment, mais avec une signification différente !) à la place de la liste d’arguments
(attention, en C + +, la règle sera différente : on se contentera de ne rien mentionner
dans la liste d’arguments). Voici l’en−tête d’une fonction ne recevant aucun argument
et renvoyant une valeur de type float (il pourrait s’agir, par exemple, d’une fonction
fournissant un nombre aléatoire !) :
float tirage (void)
Sa déclaration serait très voisine (elle ne diffère que par la présence du point-virgule !) :
float tirage (void) ;
Enfin, rien n’empêche de réaliser une fonction ne possédant ni arguments ni valeur de
retour. Dans ce cas, son en-tête sera de la forme :
void message (void)
et sa déclaration sera :
void message (void) ;
N.B
la fonction main est une fonction sans argument et sans valeur de retour. Elle devrait
donc avoir pour en−tête "void main (void)". Certains compilateurs fournissent d’ailleurs
un message d’avertissement ("warning") lorsque vous vous contentez de l’en−tête usuel
main. Exemple
#include <stdio.h>
main()
{
void fcarres (int, int) ; /* prototype de fcarres */
void erreur (void) ; /* prototype de erreur */
int debut = 5, f in = 10 ;
.....
fcarres (debut, fin) ;
.....
if (...) erreur () ;
}
void fcarres (int d, int f)
{
int i ;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 46/77
for (i = d ; i <= f ; i + +)
printf ("%d a pour carré %d\n", i, i ∗ i) ;
}
void erreur (void)
{
printf (" erreur \ n") ;
}

5.4 Déclarations des fonctions


5.4.1 Les différents façons de déclarer une fonction
Dans ce qui précède nous avions fourni la définition de la fonction fct après celle de
la fonction main. Mais nous aurions pu faire l’inverse comme suit :
float fct (float x, int b, int c)
{
....
}
main()
{
float fct (float, int, int) ; /* déclaration de la fonc. fct */
.....
y = fct (x, n, p) ;
.....
}
Dans ce cas, la déclaration de la fonction fct (ici, dans main) est facultative, car, lors-
qu’il traduit la fonction main, le compilateur connaît déjà la fonction fct. Néanmoins,
nous vous déconseillons d’omettre la déclaration de fct dans ce cas ; en effet, il est tout
à fait possible qu’ultérieurement vous soyez amené à modifier votre programme source
ou même à l’éclater en plusieurs fichiers source comme l’autorisent les possibilités de
compilation séparée du langage C.
Par ailleurs, le langage C (mais pas le C++) vous permet d’effectuer des déclarations
partielles en ne mentionnant pas le type des arguments ; ainsi, dans notre exemple du
paragraphe 2, nous pourrions déclarer fct de cette façon dans la fonction main :
float fexple () ;
Car le C vous autorise à ne pas déclarer du tout une fonction qui renvoie une valeur de
type int (là encore, ce sera interdit en C++).
Remarque :
Il est conseillé d’éviter de telles possibilités. Toutefois, sachez que vous risquez d’employer
la dernière sans y prendre garde. En effet, toute fonction que vous utiliserez sans l’avoir
déclarée sera considérée par le compilateur comme ayant des arguments quelconques et
fournissant un résultat de type int. Les conséquences en seront différentes suivant que

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 47/77
ladite fonction est ou non fournie dans le même fichier source. Dans le premier cas, on
obtiendra bien une erreur de compilation ; dans le second, en revanche, les conséquences
n’apparaîtront (de manière plus ou moins voilée) que lors de l’exécution !
La déclaration complète d’une fonction porte le nom de prototype. Il est
possible, dans un prototype, de faire figurer des noms d’arguments, les-
quels sont alors totalement arbitraires ; cette possibilité a pour seul intérêt
de pouvoir écrire des prototypes qui sont identiques à l’entête de la fonc-
tion (au point-virgule près), ce qui peut en faciliter la création automatique.
Danc notre fonction fct aurait pu être déclarée ainsi :
float fct (float x, int b, int c) ;

5.4.2 A quel endroit on place la déclaration d’une fonction


Naturellement, la déclaration d’une fonction doit être à l’intérieur des déclarations de
toute fonction qui l’utilise ; c’est ce que nous avons fait jusqu’ici. la fonction utilisatrice
était la fonction main elle−même !
Dans ces conditions, nous avions affaire à une déclaration locale dont la portée était
limitée à la fonction où elle apparaissait. Mais il est également possible d’utiliser des dé-
clarations globales, en les faisant apparaître avant la définition de la première fonction.
Par exemple, avec :
float fct (float, int, int) ;
main()
{ ...
}
void f1 (...)
{ ...
}
la déclaration de fct est connue à la fois de main et de f1.

5.4.3 Pourquoi déclare−on une fonction


Nous avons vu que la déclaration d’une fonction est plus ou moins obligatoire et
qu’elle peut être plus ou moins détaillée. Malgré tout, nous vous avons recommandé
d’employer toujours la forme la plus complète possible qu’on nomme prototype. Dans ce
cas, un tel prototype peut être utilisé par le compilateur, et cela de deux façons complè-
tement différentes.

— Si la définition de la fonction se trouve dans le même fichier source (que ce soit


avant ou après la déclaration), il s’assure que les arguments muets ont bien le type
défini dans le prototype. Dans le cas contraire, il signale une erreur.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 48/77
— Lorsqu’il rencontre un appel de la fonction, il met en place d’éventuelles conver-
sions des valeurs des arguments effectifs dans le type indiqué dans le prototype.
Par exemple, avec notre fonction fct du paragraphe précédent, un appel tel que :
fct(n + 1, 2 ∗ x, p)
Sera traduit par :
- l’évaluation de la valeur de l’expression n + 1 (en int) et sa conversion en float,
- l’évaluation de la valeur de l’expression 2 ∗ x (en float) et sa conversion en int ; il y a
donc dans ce dernier cas une conversion dégradante 2 .

5.5 Réflexions sur les fichiers en−tête


Nous avons déjà dit qu’il existe un certain nombre de fichiers d’extension .h, corres-
pondant chacun à une classe de fonctions. On y trouve, entre autres choses, les prototypes
de ces fonctions. Ce point sera très utile :

— d’une part pour effectuer des contrôles sur le nombre et le type des arguments
mentionnés dans les appels de ces fonctions,
— d’autre part pour forcer d’éventuelles conversions auxquelles on risque de ne pas
penser.
À titre d’illustration de ce dernier aspect, supposez que vous ayez écrit ces instructions :
float x, y ;
...
y = sqrt(x) ;
...
sans les faire précéder d’une quelconque directive # include.
Elles produiraient alors des résultats faux. En effet, il se trouve que la fonction sqrt
s’attend à recevoir un argument de type double (ce qui sera le cas ici, compte tenu des
conversions implicites), et elle fournit un résultat de type double. Or, lors de la traduction
de votre programme, le compilateur ne le sait pas. Il attribue donc d’office à sqrt le type
int et il met en place une conversion de la valeur de retour (laquelle sera en fait de type
double) en int.
On se trouve en présence des conséquences habituelles d’une mauvaise interprétation de
type. Un premier remède consiste à placer dans votre module la déclaration :
double sqrt(double) ;
mais encore faut-il que vous connaissiez de façon certaine le type de cette fonction.
Une meilleure solution consiste à placer, en début de votre programme, la directive :

2. Rappelons que, lorsque le compilateur ne connaît pas le type des arguments d’une fonction, il
utilise des règles de conversions systématiques : char et short → int et float → double. La fonction printf
est précisément dans ce cas.
Compte tenu ça, seule une fonction déclarée avec un prototype pourra recevoir un argument de type
float, char ou short.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 49/77
#include <math.h>
laquelle incorporera automatiquement le prototype approprié (entre autres choses).

5.6 Les arguments en C


Nous avons déjà eu l’occasion de dire qu’en C les arguments d’une fonction étaient
transmis par valeur. Cependant, dans les exemples que nous avons rencontrés dans ce
chapitre, les conséquences et les limitations de ce mode de transmission n’apparaissaient
guère. Or voyez cet exemple :
#include <stdio.h> Conséquences de la transmission par valeur des arguments*
main()
{
void echange (int a, int b) ;
int n = 10, p = 20 ;
printf ("avant appel : %d %d \ n", n, p) ;
echange (n, p) ;
printf ("après appel : %d %d", n, p) ;
}
void echange (int a, int b)
{
int c ;
printf ("début echange : %d %d\ n", a, b) ;
c = a;
a = b;
b = c;
printf ("fin echange : %d %d \n", a, b) ;
}
Après exécution on aura le résultat suivant :
avant appel : 10 20
début echange : 10 20
fin echange : 20 10
après appel : 10 20
La fonction echange reçoit deux valeurs correspondant à ses deux arguments muets a
et b. Elle effectue un échange de ces deux valeurs. Mais, lorsque l’on est revenu dans le
programme principal, aucune trace de cet échange ne subsiste sur les arguments effectifs
n et p.
En effet, lors de l’appel de echange, il y a eu transmission de la valeur des expressions n
et p. On peut dire que ces valeurs ont été recopiées localement dans la fonction echange
dans echange, de sorte que les valeurs des variables n et p n’ont, quant à elles, pas été
modifiées.
C’est ce qui explique le résultat constaté. Ce mode de transmission semble donc interdire
a priori qu’une fonction produise une ou plusieurs valeurs en retour, autres que celle de

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 50/77
la fonction elle− même. Or, il ne faut pas oublier qu’en C tous les modules doivent être
écrits sous forme de fonction.
Autrement dit, ce simple problème d’échange des valeurs de deux variables doit pouvoir
se résoudre à l’aide d’une fonction.
Nous verrons que ce problème possède plusieurs solutions, à savoir : Transmettre en ar-
gument la valeur de l’adresse d’une variable. La fonction pourra éventuellement agir sur
le contenu de cette adresse. C’est précisément ce que nous faisons lorsque nous utilisons
la fonction scanf. Nous examinerons cette technique en détail dans le chapitre consacré
aux pointeurs.
Utiliser des variables globales, comme nous le verrons dans le prochain paragraphe ; cette
deuxième solution devra toutefois être réservée à des cas exceptionnels, compte tenu des
risques qu’elle présente (effets de bords).
Remarques :
C’est bien parce que la transmission des arguments se fait "par valeur" que les arguments
effectifs peuvent prendre la forme d’une expression quelconque. Dans les langages où le
seul mode de transmission est celui "par adresse", les arguments effectifs ne peuvent être
que l’équivalent d’une lvalue.
La norme n’impose aucun ordre pour l’évaluation des différents arguments d’une fonction
lors de son appel. En général, ceci est de peu d’importance, excepté dans une situation
(fortement déconseillée !) telle que :
int i = 10 ;
...
f (i + +, i) ; /* on peut calculer i + + avant i −→ f (10, 11) */
/* ou après i −→ f (10, 10)*/

5.7 Les variables


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 C, plu-
sieurs fonctions (dont, bien entendu le programme principal main) peuvent partager des
variables communes qu’on qualifie alors de globales 3

5.7.1 Exemple d’utilisation de variables globales


Considérons le programme suivant qui nous donne un exemple d’utilisation d’une
variable globale.
#include < stdio.h >
int i ;
3. La norme ANSI ne parle pas de variables globales, mais de variables externes. Le terme "global"
illustre plutôt le partage entre plusieurs fonctions tandis que le terme "externe" illustre plutôt le partage
entre plusieurs fichiers source. En C, une variable globale est partagée par plusieurs fonctions ; elle peut
être (mais elle n’est pas obligatoirement) partagée entre plusieurs fichiers source.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 51/77
main() {
void opt(void) ;
f or(i = 1; i <= 5; i + +)
opt() ;
}
void opt(void)
{
printf ("il fait beau %d fois \n", i) ;
}
Après exécution il donne le résultat suivant :
il fait beau 1 fois
il fait beau 2 fois
il fait beau 3 fois
il fait beau 4 fois
il fait beau 5 fois
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.
Alors, le programme principal affecte à i des valeurs qui se trouvent utilisées par la
fonction opt.
Notez qu’ici la fonction opt se contente d’utiliser la valeur de i mais rien ne l’empêche de
la modifier. Ce qui implique l’utilisation des variables globales que dans des cas limités.
En effet, toute variable globale peut être modifiée 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 (voir
chapitre prochain : tableau et pointeur). 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.

5.7.2 La portée des variables globales


Les variables globales ne sont connues du compilateur que dans la partie du pro-
gramme source suivant leur déclaration. On dit que leur portée (ou encore leur espace
de validité) est limitée à la partie du programme source qui suit leur déclaration (n’ou-
bliez pas que, pour l’instant, nous nous limitons au cas où l’ensemble du programme est
compilé en une seule fois).
Ainsi, voyez, par exemple, ces instructions :
main()
{
...
}
int n ;
float x ;
fct1 (...)

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 52/77
{
...
}
fct2 (...)
{
...
}
Les variables n et x sont accessibles aux fonctions f ct1 et f ct2, mais pas au programme
principal. En pratique, bien qu’il soit possible effectivement de déclarer des variables
globales à n’importe quel endroit du programme source qui soit extérieur aux fonctions,
on procédera rarement ainsi. En effet, pour d’évidentes raisons de lisibilité, on préférera
regrouper les déclarations de toutes les variables globales au début du programme source.

5.7.3 La classe d’allocation des variables globales


A noter, généralement, que les variables globales existent pendant toute l’exécution
du programme dans lequel elles apparaissent. Leurs emplacements en mémoire sont par-
faitement définis lors de l’édition de liens. On traduit cela en disant qu’elles font
partie de la classe d’allocation statique.
De plus, ces variables se voient initialisées à zéro, avant le début de l’exécution du pro-
gramme, sauf, bien sûr, si vous leur attribuez explicitement une valeur initiale au moment
de leur déclaration.

5.8 Les variables locales


À 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.

5.8.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.
Considérons l’exemple suivant :
int n ;
main()
{
int p ;
...
}

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 53/77
f ct1 ()
{
int p ;
int n ;
}
La variable p de main n’a aucun rapport avec la variable p de f ct1. De même, la variable
n de f ct1 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.

5.8.2 Les variables locales automatiques


Les variables locales sont limitée à l’exécution de la fonction dans laquelle elles fi-
gurent.
Plus précisément, leurs emplacements ne sont pas définis de manière permanente comme
ceux des variables globales. Un nouvel espace mémoire leur est alloué à chaque entrée
dans la fonction et libéré à chaque sortie. Il sera donc généralement différent d’un appel
au suivant.
On traduit cela en disant que la classe d’allocation de ces variables est automatique. Nous
aurons l’occasion de revenir plus en détail sur cette gestion dynamique de la mémoire.
D’autre part, les valeurs transmises en arguments à une fonction sont traitées de la même
manière que les variables locales. Leur durée de vie correspond également à celle de la
fonction.

5.8.3 Les variables locales statiques


Il est toutefois possible de demander d’attribuer un emplacement permanent à une
variable locale et qu’ainsi sa valeur se conserve d’un appel au suivant.
Il suffit pour cela de la déclarer à l’aide du mot-clé static (le mot static employé sans
indication de type est équivalent à static int).
Exemple :
#include <stdio.h>
main()
{
void fct(void) ;
int n ;
for (n = 1; n <= 5; n + +)
fct() ;
}
void fct(void)
{
static int i ;
i + +;
printf ("call number : %d\n", i) ;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 54/77
}
Après exécution nous aurons le résultat suivant :
call number : 1
call number : 2
call number : 3
call number : 4
call number : 5
La variable locale i a été déclarée de classe "statique". On constate bien que sa valeur
progresse de un à chaque appel. De plus, on note qu’au premier appel sa valeur est nulle.
En effet, comme pour les variables globales (lesquelles sont aussi de classe
statique) : les variables locales de classe statique sont, par défaut, initialisées
à zéro.
Il faut bien noter : à ne pas confondre une variable locale de classe statique avec
une variable globale. En effet, la portée d’une telle variable reste toujours limitée à la
fonction dans laquelle elle est définie. Ainsi, dans notre exemple, nous pourrions définir
une variable globale nommée i qui n’aurait alors aucun rapport avec la variable i de fct.

5.8.4 Les fonctions récursive


La programmation avec C autorise des appels de fonctions d’une manière récursive
comme suit :

1. Une récursivité directe : une fonction comporte, dans sa définition, au moins un


appel à elle-même,
2. Une récursivité croisée : l’appel d’une fonction entraîne celui d’une autre fonc-
tion qui, à son tour, appelle la fonction initiale (le cycle pouvant d’ailleurs faire
intervenir plus de deux fonctions).
Exemple :
long fact(int n)
{
if (n>1)
return (fact(n-1)*n) ;
else
return(1) ;
}
Dans chaque appel de fact entraîne une allocation d’espace pour les variables locales et
pour son argument n. Alors chaque nouvel appel de fact, à l’intérieur de fact, provoque
une telle allocation, sans que les emplacements précédents soient libérés.
Il y a donc un empilement des espaces alloués aux variables locales, parallèlement à un
empilement des appels de la fonction. Ce n’est que lors de l’exécution de la première
instruction return que l’on commencera à "dépiler" les appels et les emplacements et

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 55/77
donc à libérer de l’espace mémoire.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 56/77
CHAPITRE 6
LES TABLEAUX

Sommaire
6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.2 Les tableaux à une dimension . . . . . . . . . . . . . . . . . . 58
6.2.1 Définitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
6.2.2 Déclaration et mémorisation . . . . . . . . . . . . . . . . . . . . 58
6.2.3 Mémorisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3 Initialisation et réservation automatique . . . . . . . . . . . 59
6.3.1 Initialisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3.2 Réservation automatique . . . . . . . . . . . . . . . . . . . . . 60
6.4 Accès aux composantes . . . . . . . . . . . . . . . . . . . . . . 60
6.4.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.4.2 Remarque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.5 Affichage et affectation . . . . . . . . . . . . . . . . . . . . . . 61
6.6 Les tableaux à deux dimensions . . . . . . . . . . . . . . . . . 62
6.6.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.6.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.6.3 Déclaration et mémorisation . . . . . . . . . . . . . . . . . . . . 63
6.6.4 Initialisation et réservation automatique . . . . . . . . . . . . . 64
6.6.5 accès aux composantes . . . . . . . . . . . . . . . . . . . . . . . 66

6.1 Introduction
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

57
autres langages de programmation. Nous allons cependant voir plus loin (Chapitre sui-
vant. Les Pointeurs), que le langage C permet un accès encore plus direct et plus rapide
aux données d’un tableau.
Il est possible d’utiliser des tableaux de valeurs. Pour déclarer un tableau il faut donner
le type de ses éléments puis son nom et enfin sa taille entre crochets. Tous les éléments
d’un tableau sont obligatoirement du même type.
Pour un tableau de taille N, l’indice du premier élément est 0 et celui du dernier est (N
-1). On peut utiliser des tableaux de dimension 2 ou plus.

6.2 Les tableaux à une dimension


6.2.1 Définitions
Un tableau (uni-dimensionnel) A est une variable structurée formée d’un nombre en-
tier 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.
A: ... N composantes.
En faisant le rapprochement avec les mathématiques, on dit encore que "A est un vecteur
de dimension N".

Exemple

La déclaration
int JOURS[12]=31,28,3,2,15,14,14,17,18,9,11,12 ;
définit un tableau du type int de dimension 12. Les 12 composantes sont initialisées par
les valeurs respectives 31, 28, 3, ... , 12.
On peut accéder à la première composante du tableau par JOURS[0], à la deuxième
composante par JOURS[1], . . . , à la dernière composante par JOURS[11].

6.2.2 Déclaration et mémorisation


Déclaration

En algorithmique on peut déclarer un tableau sous la forme suivante :


<TypeSimple> tableau <NomTableau>[<Dimension>]
En langage C on peut déclarer un tableau de la manière suivante :
<TypeSimple> <NomTableau>[<Dimension>] ;
Les noms des tableaux sont des identificateurs qui ne contiennent que les symboles sui-
vants :
0,1,2,...,9,A,B,...,Z,_,a,b,...,z
il remarquer ici que le langage C distingue les majuscules et les minuscules, c’est à dire

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 58/77
que ’Nom_de_variable’ est différent de ’nom_de_variable’

Exemples

Les déclarations suivantes en langage algorithmique,


entier tableau A[25]
réel tableau B[100]
booléen tableau C[10]
caractère tableau D[30]
Leurs traduction en langage C est la suivante :
int A[25] ; ou bien long A[25] ; ou bien ...
float B[100] ; ou bien double B[100] ; ou bien ...
int C[10] ;
char D[30] ;

6.2.3 Mémorisation
En langage 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.

Exemple1

Considérons l’exemple suivant :


short A[5] = 1200, 2300, 3400, 4500, 5600 ;
... 1200 2300 3400 4500 5600 ...
Adresse : 1E04 1E06 1E08 1E0A 1E0C 1E0E 1E10
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.

Exemple2

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] ; Le langage C réservera N ∗ M = 15 ∗ 4 = 60 octets en mémoire.

6.3 Initialisation et réservation automatique


6.3.1 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.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 59/77
Exemples

int A[5] = 10, 20, 30, 40, 50 ;


float B[4] = -1.05, 3.33, 87e-5, -12.3E4 ;
int C[10] = 1, 0, 0, 1, 1, 1, 0, 1, 0, 1 ;
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.

6.3.2 Réservation automatique


Si la dimension n’est pas indiquée explicitement lors de l’initialisation, alors l’ordina-
teur réserve automatiquement le nombre d’octets nécessaires.

Exemple1

int A[] = 10, 20, 30, 40, 50 ;


⇒ réservation de 5 ∗ sizeof (int) octets (dans notre cas : 10 octets) float B[] = -1.05,
3.33, 87e-5, -12.3E4 ;
⇒ réservation de 4 ∗ sizeof (f loat) octets (dans notre cas : 16 octets) int C[] = 1, 0, 0,
1, 1, 1, 0, 1, 0, 1 ;
⇒ réservation de 10 ∗ sizeof (int) octets (dans notre cas : 20 octets)

Exemple2

short A[]=200, 300, 400, 500, 600 ;


A : 200 300 400 500 600
short A[5]=200, 300, 400 ;
A : 1200 2300 3400 0 0
short A[3]=200, 300, 400, 500, 600 ;
A : 1200 2300 3400 ? ?
Cette dernière déclaration provoquera une erreur !

6.4 Accès aux composantes


Prenons la déclaration suivante d’un tableau de type int :
int A[5] ;
Dans cette déclaration nous avons défini un tableau A avec cinq composantes, auxquelles
on peut accéder par :
A[0], A[1], A[2], A[3] et A[4]

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 60/77
6.4.1 Exemple
short A[5]={200, 300, 400, 500, 600} ;
200 300 400 500 600
A:
A[0] A[1] A[2] A[3] A[4]

6.4.2 Remarque
Considérons un tableau T de dimension N :
En langage 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].
En algorithmique :
 : l’accès au premier élément du tableau se fait par T[1].
 : l’accès au dernier élément du tableau se fait par T[N].

6.5 Affichage et affectation


Pour faire des manipulation sur les tableaux on peut utiliser La structure for. La
plupart des applications se laissent implémenter par simple modification des exemples-
types de l’affichage et de l’affectation.

Affichage du contenu d’un tableau

Ce programme permet d’afficher les éléments d’un tableau contenant 5 éléments :


main()
{
int A[5] ;
int I ; /* Compteur */
for (I=0 ; I<5 ; I++)
printf("%d ", A[I]) ;
return 0 ;
printf("\n") ;
}
Avant de pouvoir afficher les composantes d’un tableau, il faut évidemment leur affecter
des valeurs.

• Rappelez-vous que la deuxième condition dans la structure for n’est pas une condi-
tion d’arrêt, mais une condition de répétition ! Ainsi la commande d’affichage sera répétée
aussi longtemps que I est inférieur à 5. La boucle sera donc bien exécutée pour les indices
0,1,2,3 et 4 !
• Par opposition à la commande simplifiée écrire A[I] du langage algorithmique, la com-
mande printf doit être informée du type exact des données à afficher. (Ici : %d ou %i

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 61/77
pour des valeurs du type int)
• Pour être sûr que les valeurs sont bien séparées lors de l’affichage, il faut inclure au
moins un espace dans la chaîne de format. Autres possibilités :
printf ("%d", A[I]) ; /* tabulateur */
printf ("%7d", A[I]) ; /* format d’affichage */

Affectation dans un tableau

Considérons le programme suivant :


main()
{
int A[5] ;
int I ; /* Compteur */
for (I=0 ; I<5 ; I++)
scanf("%d", &A[I]) ;
return 0 ;
}
Remarque :
• Comme scanf a besoin des adresses des différentes composantes du tableau, il faut
faire précéder le terme A[I] par l’opérateur adresse ’&’.
• La commande de lecture scanf doit être informée du type exact des données à lire.
(Ici : %d ou %i pour lire des valeurs du type int)

6.6 Les tableaux à deux dimensions


6.6.1 Définition
En langage C, un tableau à deux dimensions A est à interpréter comme un ta-
bleau (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.
...
...
...
A:
... ... ... ... ... ...
...
...
Le tableau à deux dimensions est dite carré, si L est égal à C.
Mathématiquement parlons, on peut dire que "A est un vecteur de L vecteurs de dimen-
sion C", ou mieux :

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 62/77
"A est une matrice de dimensions LxC".

6.6.2 Exemple
Considérons un tableau NOTE à une dimension pour mémoriser les notes de 20 élèves
d’une classe dans un contrôle :
int NOTE[20]=12, 15, ..., 13, 18 ;

12 15 ... 13 18
NOTE :
A[0] A[1] ... A[18] A[19]
Pour mémoriser les notes des élèves dans les 6 contrôles d’un trimestre, nous pouvons
rassembler plusieurs de ces tableaux uni-dimensionnels dans un tableau NOTES à deux
dimensions :
int NOTE[6][20]=12, 15, ..., 13, 18,
15, 12, ..., 11, 15,
... ... ...
12, 15, ..., 13, 16 ;

12 15 ... 13 18
15 12 ... 11 15
NOTE :
... ... ... ... ...
12 15 ... 13 16
Dans une ligne nous retrouvons les notes de tous les élèves dans un contrôle. Dans
une colonne, nous retrouvons toutes les notes d’un élève.

6.6.3 Déclaration et mémorisation


Déclarations

En langage C on peut déclarer un tableau à deux dimensions de la manière suivante :


<TypeSimple> <NomTabl>[<DimLigne>][<DimCol>] ;

Exemples

Dans les instructions suivantes nous donnons quelques exemples de tableau à deux
dimensions en langage C.
int A[10][10] ;
ou bien
long A[10][10] ;
ou bien

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 63/77
...
float B[2][20] ;
ou bien
double B[2][20] ;
ou bien
...
int C[3][3] ;
char D[15][40] ;

Mémorisation

Comme pour les tableaux à une dimension, le nom d’un tableau est le représentant
de l’adresse du premier élément du tableau (c.-à-d. l’adresse de la première ligne du ta-
bleau). Les composantes d’un tableau à deux dimensions sont stockées ligne par ligne
dans la mémoire.
Exemple 1 : Mémorisation d’un tableau à deux dimensions
short A[3][2]=1, 2 ,
10, 20 ,
100, 200 ;
... 1 2 10 20 100 200 ...
A : Adresse : 1E06 1E08 1E0A 1E0C 1E0E 1E10 1E12
Un tableau de dimensions L et C, formé de composantes dont chacune a besoin de M
octets, occupera L ∗ C ∗ M octets en mémoire.
Exemple 2 : En supposant qu’une variable du type double occupe 8 octets (c.-à-d : si-
zeof(double)=8), pour le tableau T déclaré par : double T[10][15] ; Le langage C réservera
L ∗ C ∗ M = 10 ∗ 15 ∗ 8 = 1200 octets en mémoire.

6.6.4 Initialisation et réservation automatique


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 plu-
sieurs 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,

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 64/77
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 man-
quantes seront initialisées par zéro. Il est cependant défendu d’indiquer trop de valeurs
pour un tableau.
int B[4][4]=1,0,0,0
1,1,0,0
1,1,1,0
1,1,1,1 ;

1 0 0 0
1 1 0 0
B:
1 1 1 0
1 1 1 1
int B[4][4]=1,1,1,1 ;
1 1 1 1
0 0 0 0
B:
0 0 0 0
0 0 0 0
int B[4][4]=1,1,1,1 ;

1 0 0 0
1 0 0 0
B: int B[4][4]=1,1,1 ;
1 0 0 0
1 0 0 0
Cette déclaration provoquera une erreur ! !

Réservation automatique
Si le nombre de lignes L n’est pas indiqué explicitement lors de l’initialisation, l’or-
dinateur réserve automatiquement le nombre d’octets nécessaires.
int A[][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 ;
réservation de 3*10*2 = 60 octets
float B[][2] = -1.05, -1.10 ,
86e-5, 87e-5 ,
-12.5E4, -12.3E4 ;
réservation de 3*2*4 = 24 octets
Pour l’exemple suivant :

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 65/77
int B[4][4]=1,0,0,0
1,1,0,0
1,1,1,0
1,1,1,1 ;

1 0 0 0
1 1 0 0
B:
1 1 1 0
1 1 1 1
On aura une reservation de 4 ∗ 4 ∗ 2 = 32octets.

6.6.5 accès aux composantes


Pour accéder à élément du d’un tableau de deux dimensions on utilise l’instruction
suivante :
<NomTableau>[<Ligne>][<Colonne>]
Les
 éléments d’un tableau de dimensions L et C se présentent  de la façon suivante :
A[0][0] A[0][1] A[0][2] ... A[0][C − 1]
A[1][C − 1]
 
 A[1][0] A[1][1] A[1][2] ... 
 
 A[2][0] A[2][1] A[2][2] ... A[2][C − 1]
 

 

 ... ... ... ... .... 

A[L − 1][0] A[L − 1][1] A[L − 1][2] ... A[L − 1][C − 1]
Remarque :
Considérons un tableau A de dimensions L et C. En langage C :
♣ les indices du tableau varient de 0 à L-1, respectivement de 0 à C-1.
♣ la composante de la Nième ligne et Mième colonne est notée :
A[N-1][M-1]
En algorithmique,
- les indices du tableau varient de 1 à L, respectivement de 1 à C.
- la composante de la Nième ligne et Mième colonne est notée :
A[N,M]

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 66/77
CHAPITRE 7
LES POINTEURS

Sommaire
7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2 Stockage des variables en mémoire . . . . . . . . . . . . . . . 68
7.3 Définition et déclaration d’un pointeur . . . . . . . . . . . . 68
7.4 Opérateur d’adresse : & . . . . . . . . . . . . . . . . . . . . . 68
7.5 opérateur d’indirection ; * . . . . . . . . . . . . . . . . . . . . 69
7.6 Mémoire et pointeurs . . . . . . . . . . . . . . . . . . . . . . . 69
7.6.1 Commentaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.6.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.7 Adressage des composantes d’un tableau . . . . . . . . . . . 70
7.7.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.7.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.7.3 Formalisme tableau et formalisme pointeur . . . . . . . . . . . 72
BIBLIOGRAPHIE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

7.1 Introduction
es pointeurs représentent en effet une des notions les plus délicates du langage C. Si
L j’insiste autant sur leur importance, c’est parce qu’il est impossible de programmer
en langage C sans les connaître et bien les comprendre.
La plupart des langages de programmation offrent la possibilité d’accéder aux données
dans la mémoire de l’ordinateur à l’aide de pointeurs, c.-à-d. à l’aide de variables aux-
quelles on peut attribuer les adresses d’autres variables. En C, les pointeurs jouent un
rôle primordial dans la définition de fonctions : Comme le passage des paramètres en C
se fait toujours par la valeur, les pointeurs sont le seul moyen de changer le contenu de
variables déclarées dans d’autres fonctions. Ainsi le traitement de tableaux et de chaînes
de caractères dans des fonctions serait impossible sans l’utilisation de pointeurs.

67
7.2 Stockage des variables en mémoire
Lors de la compilation d’un programme, l’ordinateur réserve dans sa mémoire une
place pour chaque variable déclarée. C’est à cet endroit que la valeur de la variable est
stockée. Il associe alors au nom de la variable l’adresse de stockage. Ainsi, pendant le
déroulement du programme, quand il rencontre un nom de variable, il va chercher à
l’adresse correspondante la valeur en mémoire. Pour les déclarations de variables sui-
vantes :
int a = 0xa ; /* ’a’ est un entier codé sur 4 octets */
short b = 0x0 ; /* ’b’ est un entier codé sur 2 octets */
int c = 0x14 ; /* ’c’ est un entier codé sur 4 octets */
ceci est stocké en mémoire : Ici, on suppose que l’espace mémoire servant à stocker les

données commence à l’adresse (bfbff000). Chaque case représente 1 octet.


Explication du schéma :
• a est codé sur 4 octets et son adresse est (bfbff000), donc l’adresse de b sera (bfbff000)+(4)=(bfbff004)
• b est codé sur 2 octets et son adresse est (20004), donc l’adresse de c sera (bfbff004)+(2)=(bfbff006).

7.3 Définition et déclaration d’un pointeur


Un pointeur est une variable qui a pour valeur l’adresse d’une autre variable : celle
sur laquelle elle pointe ! Un pointeur est toujours associé à un type de variable et un seul.
Au moment de la déclaration, on détermine le type de variable pointé par le pointeur,
en écrivant le type concerné, puis le nom du pointeur avec une * devant :
int *pta ; /* la variable pta est un pointeur sur un entier*/
int a ; /* la variable a est un entier*/

7.4 Opérateur d’adresse : &


Pour affecter l’adresse de la variable a au pointeur pta, on écrit l’instruction :
pta = &a;
cet opérateur signifie : l’adresse de.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 68/77
7.5 opérateur d’indirection ; *
Cet opérateur, mis en préfixe d’un nom de pointeur signifie valeur de la variable
pointée ou, plus simplement, valeur pointée.
int a=1 ;
int *ptint ; /* declaration d’un pointeur sur un entier */
ptint=&a ; /* ptint pointe sur a */
*ptint=12 ; /* la variable pointée par ptint reçoit 12*/
printf ("a = %d \ n",a) ; /* affiche "a=12" */
En fait, manipuler ptint revient à manipuler a.

7.6 Mémoire et pointeurs


Prenons l’exemple déjà cité avant :
int a = 0xa ;
short b = 0x0 ;
int c = 0x14 ;
int *ptint ;
ptint = &a ;
Etat de la mémoire :

Figure 7.1 – Etat de la mémoire :

7.6.1 Commentaire
Les cases mémoire des variables a, b et c contiennent leur valeur. Celles de la variable
ptint contiennent l’adresse de la valeur pointée.
En effet, la valeur stockée est (bfbff000), ce qui est bien l’adresse de a.

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 69/77
7.6.2 Exemple
Prenons l’exemple d’illustration présenté comme suit :
#include <stdio.h>
main()
{
float *px ;
float x = 3.5 ;
px = &x ;
printf ("adresse de x : 0x%lx \n",&x) ;
printf ("valeur de px : 0x%lx \n",px) ;
printf ("valeur de x : %3.1f \n",x) ;
printf ("valeur pointee par px : %3.1f \n",*px) ;
return 0 ;
}
Le programme précédent affichera, après exécution’ ceci à l’écran :
adresse de x : 0xbf bf f a3c
valeur de px : 0xbf bf f a3c
valeur de x : 3.5
valeur pointee par px : 3.5

7.7 Adressage des composantes d’un tableau


Comme nous l’avons déjà constaté au chapitre 6, le nom d’un tableau représente
l’adresse de son premier élément. En d’autre 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.

7.7.1 Exemple
En déclarant un tableau A de type int et un pointeur P sur int,
int A[10] ;
int *p ;
l’instruction :
P = A; est équivalente à P = &A[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 iieme composante derrière P et
P − i pointe sur la iieme composante devant P.
Ainsi, après l’instruction, P = A ;

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 70/77
le pointeur P pointe sur A[0], et
∗(P + 1) désigne le contenu de A[1]
∗(P + 2) désigne le contenu de A[2]
...
∗(P + i) désigne le contenu de A[i].
Remarque :
Au premier coup d’oeil, il est bien surprenant que P+i n’adresse pas le ii eme octet der-
rière P, mais la ii eme composante derrière P ...
Ceci s’explique par la stratégie de programmation ’défensive’ des créateurs du langage
C:
Si on travaille avec des pointeurs, les erreurs les plus perfides sont causées par des poin-
teurs malplacés et des adresses mal calculées. En C, le compilateur peut calculer auto-
matiquement l’adresse de l’élément P+i en ajoutant à P la grandeur d’une composante
multipliée par i. Ceci est possible, parce que :
♣ chaque pointeur est limité à un seul type de données, et
♣ le compilateur connaît le nombre d’octets des différents types.

7.7.2 Exemple
Soit A un tableau contenant des éléments du type float et P un pointeur sur float :
float A[20],X ;
float *P ;
Les instructions, P = A ;
X = ∗(P + 9 ;
X contient la valeur du 10ieme élément de A, (c.-à-d. celle de A[9]). Une donnée du type
float ayant besoin de 4 octets, le compilateur obtient l’adresse P +9 en ajoutant 9∗4 = 36
octets à l’adresse dans P.
Rassemblons les constatations ci dessus :
Comme A représsente l’adresse de A[0],
∗(A + 1) désigne le contenu de A[1]
∗(A + 2) désigne le contenu de A[2]
...
∗(A + i) désigne le contenu de A[i]
A noter !
Il existe toujours une différence essentielle entre un pointeur et le nom d’un tableau :

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 71/77
— Un pointeur est une variable, donc des opérations comme P = A ou P + + sont
permises.
— Le nom d’un tableau est une constante, donc des opérations comme A = P ou
A + + sont impossibles.
Lors de la première phase de la compilation, toutes les expressions de la forme A[i]
sont traduites en ∗(A + i). En multipliant l’indice i par la grandeur d’une composante,
on obtient un indice en octets : <indice en octets> = <indice élément> * <grandeur
élément>
Cet indice est ajouté à l’adresse du premier élément du tableau pour obtenir l’adresse
de la composante i du tableau. Pour le calcul d’une adresse donnée par une adresse plus
un indice en octets, on utilise un mode d’adressage spécial connu sous le nom ’adressage
indexé’ :

<adresse indexée> = <adresse> + <indice en octets>

Presque tous les processeurs disposent de plusieurs registres spéciaux (registres in-
dex) à l’aide desquels on peut effectuer l’adressage indexé de façon très efficace.

En résumé : Soit un tableau A d’un type quelconque et i un indice pour les compo-
santes de A, alors
A désigne l’adresse de A[0]
A + i désigne l’adresse de A[i]
∗(A + i) désigne le contenu de A[i].
Si P = A, alors
P pointe sur l’élément A[0]
P + i pointe sur l’élément A[i]
∗(P + i) désigne le contenu de A[i]

7.7.3 Formalisme tableau et formalisme pointeur


A l’aide de ce bagage, il nous est facile de ’traduire’ un programme écrit à l’aide du
’formalisme tableau’ dans un programme employant le ’formalisme pointeur’.

Exemple

Les deux programmes suivants copient les éléments positifs d’un tableau T dans un
deuxième tableau POS. • Formalisme tableau :
main()
{
int T [10] = −3, 4, 0, −7, 3, 8, 0, −1, 4, −9 ;
int POS[10] ;
int I,J ; /* indices courants dans T et POS */
for (J = 0,I = 0 ; I < 10 ; I + +)

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 72/77
if (T[I]>0)
{
P OS[J] = T [I] ;
J++ ;
}
return 0 ;
}
Nous pouvons remplacer systématiquement la notation tableau[I] par ∗(tableau + I), ce
qui conduit à ce programme : • Formalisme pointeur :
main()
{
int T[10] = -3, 4, 0, -7, 3, 8, 0, -1, 4, -9 ;
int POS[10] ;
int I,J ; /* indices courants dans T et POS */
for (J=0,I=0 ; I<10 ; I++)
if (*(T+I)>0)
{
∗(P OS + J) = ∗(T + I) ;
J++ ;
}
return 0 ;
}
• Sources d’erreurs
Un bon nombre d’erreurs lors de l’utilisation de C provient de la confusion entre soit
contenu et adresse, soit pointeur et variable. Revoyons donc les trois types de déclara-
tions que nous connaissons jusqu’ici et résumons les possibilités d’accès aux données qui
se présentent. Les variables et leur utilisation int A ; déclare une variable simple du type
int
A désigne le contenu de A
&A désigne l’adresse de A
int B[] ;
déclare un tableau d’éléments du type int
B désigne l’adresse de la première composante de B.(Cette adresse est toujours constante)
B[i] désigne le contenu de la composante i du tableau
&B[i] désigne l’adresse de la composante i du tableau
en utilisant le formalisme pointeur :
B + i désigne l’adresse de la composante i du tableau
∗(B + i) désigne le contenu de la composante i du tableau int *P ;
déclare un pointeur sur des éléments du type int. P peut pointer sur des variables simples
du type int ou sur les composantes d’un tableau du type int. P désigne l’adresse contenue
dans P (Cette adresse est variable) *P désigne le contenu de l’adresse dans P
Si P pointe dans un tableau, alors
P désigne l’adresse de la première composante

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 73/77
P + i désigne l’adresse de la ii eme composante derrière P
∗(P + i) désigne le contenu de la ii eme composante derrière P

S. SAFI Cours : Programmation en Langage C Sept. 2025


Page 74/77
BIBLIOGRAPHIE

1 Brian W. Kernighan, Dennis M. Ritchie The C rogramming language, second


Edition, Printice Hall, 1988.
2 Borland C++ Version 3.1, Programmer’s Guide, 1992.
3 Borland C++ Version 3.1, User’s Guide, 1992.
4 Borland C++ Version 3.1, Library Reference, 1992.
5 Claude Delannoy Exercices en Langage C Edition EYROLLES, 1992
6 Jean-Michel Gaudin Infoguide Turbo - C Editions P.S.i, 1988

75
S. SAFI Cours : Programmation en Langage C Sept. 2025
Page 76/77
BIBLIOGRAPHIE

77

Vous aimerez peut-être aussi