Chapitre 20
UA 3: PROGRAMMATION EN LANGAGE C
Lecture : 18 minQuiz de 10 questions
## Objectifs et prérequis
**Objectifs** : à la fin de ce chapitre l’élève sera capable de
- installer et vérifier un compilateur C sur son poste de travail ;
- expliquer ce qu’est une bibliothèque standard et utiliser les fonctions d’entrée/sortie de `<stdio.h>` ;
- écrire, lire et déboguer des programmes contenant les trois structures itératives (`while`, `do‑while`, `for`) ainsi que les instructions `break` et `continue` ;
- résoudre des problèmes algorithmiques simples en appliquant ces notions.
**Prérequis** : notions de base d’algorithmique (variables, affectation, opérateurs arithmétiques et logiques, instruction conditionnelle `if…else`), maîtrise de la saisie au clavier et de l’affichage à l’écran, familiarité avec l’environnement de travail (explorateur de fichiers, invite de commandes ou terminal).
---
## Introduction contextualisée
La programmation en langage C constitue le socle sur lequel reposent de nombreux systèmes d’exploitation, embarqués et applications de haute performance. Au Cameroun, le référentiel MINESEC/IGE insiste sur une approche par compétences : l’élève ne doit pas seulement connaître la syntaxe, mais être capable de mettre en œuvre un environnement de développement, d’appeler des fonctions fournies par des bibliothèques et de contrôler le flux d’exécution grâce à des boucles. Ce chapitre regroupe les trois leçons qui permettent de passer de l’écriture d’un premier programme « Hello World » à la réalisation d’algorithmes itératifs classiques (somme, factorielle, recherche, etc.).
---
## I. Installation d’un compilateur (Leçon 9)
### A. Choix du compilateur
Le compilateur le plus répandu dans l’enseignement secondaire est **GCC** (GNU Compiler Collection), disponible gratuitement pour Windows, Linux et macOS. Une alternative légère est **Clang**, particulièrement performante sous macOS. Les deux produisent du code objet compatible avec la norme C99, suffisante pour le programme officiel.
> *Un compilateur transforme le code source lisible par l’homme en code machine exécutable par le processeur.*
### B. Installation selon le système d’exploitation
| Système | Étapes d’installation |
|---------|-----------------------|
| **Linux (Ubuntu/Debian)** | Ouvrir un terminal et taper `sudo apt update && sudo apt install build-essential` (installe gcc, g++, make, etc.). |
| **Windows** | Télécharger le **MinGW‑w64** depuis <https://mingw-w64.org/doku.php/download>, lancer l’installateur, cocher `gcc` et `g++`, puis ajouter le dossier `bin` (ex. `C:\Program Files\mingw-w64\bin`) à la variable d’environnement `PATH`. |
| **macOS** | Ouvrir le Terminal et exécuter `xcode-select --install` (installe les outils en ligne de commande incluant clang). Vérifier avec `clang --version`. |
### C. Vérification de l’installation
Dans un terminal, taper :
```bash
gcc --version # ou clang --version
```
La sortie doit afficher le numéro de version, par exemple :
```
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
```
Si la commande n’est pas reconnue, reprendre l’étape d’ajout au `PATH`.
### D. Utilisation en ligne de commande
1. Créer un fichier `hello.c` contenant :
```c
#include <stdio.h>
int main(void) {
printf("Hello, monde !\n");
return 0;
}
```
2. Compiler : `gcc -Wall -Wextra -o hello hello.c`
- `-Wall` active toutes les warnings utiles.
- `-Wextra` ajoute des warnings supplémentaires.
- `-o hello` nomme l’exécutable produit.
3. Exécuter : `./hello` (Linux/macOS) ou `hello.exe` (Windows).
Résultat attendu :
```
Hello, monde !
```
> *L’option `-Wall` est indispensable en phase d’apprentissage pour détecter tôt les erreurs potentielles.*
---
## II. Notion de bibliothèque et de fonctions d’entrée/sortie (Leçon 10)
### A. Bibliothèque standard
Une **bibliothèque** est un ensemble de fonctions pré‑compilées, déclarées dans des fichiers d’en‑tête (`.h`). En C, la bibliothèque la plus utilisée est la **libc** (standard C). Elle se divise en plusieurs en‑têtes :
- `<stdio.h>` : entrées/sorties formatées.
- `<stdlib.h>` : allocation mémoire, conversion de chaînes, génération de nombres aléatoires.
- `<string.h>` : manipulation de chaînes de caractères.
- `<math.h>` : fonctions mathématiques (nécessite `-lm` à l’édition des liens).
> *Inclure un en‑tête avec `#include <nom.h>` rend disponibles ses prototypes sans avoir à les réécrire.*
### B. Fonctions d’entrée/sortie de `<stdio.h>`
| Fonction | rôle | prototype | remarque |
|----------|------|-----------|----------|
| `int printf(const char *format, ...);` | affichage formaté sur stdout | retourne le nombre de caractères affichés | utilise des spécificateurs de conversion (`%d`, `%f`, `%c`, `%s`, …) |
| `int scanf(const char *format, ...);` | lecture formatée depuis stdin | retourne le nombre d’éléments correctement lus | nécessite l’adresse des variables (`&var`) |
| `int puts(const char *s);` | écrit une chaîne suivie d’un `\n` | retourne non‑négatif en cas de succès | plus rapide que `printf("%s\n",s)` pour du texte simple |
| `int getchar(void);` | lit un caractère depuis stdin | retourne le caractère lu ou `EOF` | utile pour des saisies caractère par caractère |
### C. Format de conversion (exemples)
- `%d` ou `%i` : entier signé décimal.
- `%ld` : entier long.
- `%f` : nombre flottant en notation décimale.
- `%lf` : double précision (identique à `%f` pour `printf`).
- `%c` : caractère unique.
- `%s` : chaîne de caractères terminée par `\0`.
- `%x` ou `%X` : entier en hexadécimal (minuscules/majuscules).
- `%%` : pour afficher le signe `%` littéral.
> *Le modificateur de longueur (`l`, `ll`, `h`) précède le spécificateur pour indiquer la taille de l’argument.*
### D. Exemples entièrement résolus
#### Exemple 1 : Lecture d’un entier et affichage de son double
```c
#include <stdio.h>
int main(void) {
int n;
printf("Entrez un entier : ");
if (scanf("%d", &n) != 1) { // vérifie la bonne lecture
printf("Erreur de saisie.\n");
return 1;
}
printf("Le double de %d est %d.\n", n, 2*n);
return 0;
}
```
**Étapes** :
1. Déclaration de `n`.
2. Invite à l’utilisateur via `printf`.
3. `scanf` lit un entier ; le retour vaut 1 si la conversion réussit.
4. En cas d’échec, message d’erreur et retour immédiat.
5. Calcul du double et affichage avec `printf`.
**Exécution** (entrée : `7`) :
```
Entrez un entier : 7
Le double de 7 est 14.
```
#### Exemple 2 : Lecture d’un réel et affichage avec deux décimales
```c
#include <stdio.h>
int main(void) {
double x;
printf("Donnez un nombre réel : ");
if (scanf("%lf", &x) != 1) {
printf("Saisie invalide.\n");
return 1;
}
printf("Vous avez entré : %.2f\n", x); // %.2f → deux chiffres après la virgule
return 0;
}
```
**Résultat** (entrée : `3.14159`) :
```
Donnez un nombre réel : 3.14159
Vous avez entré : 3.14
```
> *Toujours tester le retour de `scanf` pour éviter l’utilisation de variables non initialisées.*
---
## III. Structures itératives (Leçon 11)
### A. Boucle `while`
**Syntaxe** :
```c
while (condition) {
// bloc d’instructions exécuté tant que condition est vraie
}
```
- La condition est évaluée **avant** chaque itération.
- Si la condition est fausse dès le départ, le corps n’est jamais exécuté.
> *`while` convient lorsqu’on ne connaît pas à l’avance le nombre d’itérations nécessaires.*
#### Exemple : Somme des entiers de 1 à n
```c
#include <stdio.h>
int main(void) {
int n, i = 1, somme = 0;
printf("Entrez n : ");
scanf("%d", &n);
while (i <= n) {
somme += i;
++i; // équivalent à i = i + 1
}
printf("Somme = %d\n", somme);
return 0;
}
```
**Trace** pour `n = 4` :
| i avant | condition i≤n | somme après | i après |
|--------|---------------|------------|---------|
| 1 | vraie | 1 | 2 |
| 2 | vraie | 3 | 3 |
| 3 | vraie | 6 | 4 |
| 4 | vraie | 10 | 5 |
| 5 | fausse | — | — |
Résultat affiché : `Somme = 10`.
### B. Boucle `do‑while`
**Syntaxe** :
```c
do {
// bloc d’instructions
} while (condition);
```
- Le corps est exécuté **au moins une fois**, car la condition est testée en fin d’itération.
> *Utilisée quand on veut garantir une première exécution (ex. menu interactif).*
#### Exemple : Saisie d’un nombre positif
```c
#include <stdio.h>
int main(void) {
int val;
do {
printf("Entrez un entier strictement positif : ");
scanf("%d", &val);
} while (val <= 0); // répète tant que la saisie n’est pas >0
printf("Vous avez choisi %d.\n", val);
return 0;
}
```
Si l’utilisateur entre `-3`, puis `0`, puis `5`, la boucle s’arrête après la troisième saisie et affiche `Vous avez choisi 5.`
### C. Boucle `for`
**Syntaxe** :
```c
for (initialisation; condition; miseàjour) {
// bloc d’instructions
}
```
- Les trois parties sont optionnelles ; le point‑virgule les sépare.
- Idéale quand le nombre d’itérations est connu ou facilement exprimable.
> *La boucle `for` est souvent préférée pour sa lisibilité lorsqu’on parcourt un intervalle.*
#### Exemple : Factorielle de n (n ≥ 0)
```c
#include <stdio.h>
int main(void) {
int n, i;
unsigned long long fact = 1ULL; // assez grand pour n ≤ 20
printf("Entrez n (0 ≤ n ≤ 20) : ");
scanf("%d", &n);
if (n < 0 || n > 20) {
printf("Valeur hors intervalle autorisé.\n");
return 1;
}
for (i = 2; i <= n; ++i) {
fact *= (unsigned long long)i;
}
printf("%d! = %llu\n", n, fact);
return 0;
}
```
**Explication** :
- Initialisation `i = 2` (puisque multiplier par 1 ne change rien).
- Condition `i <= n`.
- Mise à jour `++i`.
- Accumulation dans `fact` de type `unsigned long long` pour éviter l débordement jusqu’à 20! ≈ 2,43·10¹⁸.
**Test** : `n = 5` → `5! = 120`.
### D. Instructions `break` et `continue`
- `break` : sort immédiatement de la boucle la plus interne, indépendamment de la condition.
- `continue` : passe à l’itération suivante (ignore le reste du corps courant).
> *Utiliser `break` pour sortir prématurément lorsqu’une condition de sortie est rencontrée ; `continue` pour ignorer les cas indésirables sans quitter la boucle.*
#### Exemple : Recherche du premier nombre divisible par 7 dans un tableau
```c
#include <stdio.h>
int main(void) {
int tab[] = {4, 9, 14, 20, 21, 30};
int taille = sizeof(tab)/sizeof(tab[0]);
int i;
for (i = 0; i < taille; ++i) {
if (tab[i] % 7 == 0) {
printf("Premier multiple de 7 trouvé : %d à l’indice %d\n", tab[i], i);
break; // sortie de la boucle dès la première occurrence
}
}
if (i == taille) // aucune occurrence trouvée
printf("Aucun multiple de 7 dans le tableau.\n");
return 0;
}
```
**Résultat** : `Premier multiple de 7 trouvé : 14 à l’indice 2`.
#### Exemple : Affichage des nombres de 1 à 20 sauf les multiples de 4
```c
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 20; ++i) {
if (i % 4 == 0) {
continue; // saute l’affichage quand i est multiple de 4
}
printf("%d ", i);
}
putchar('\n');
return 0;
}
```
**Sortie** :
```
1 2 3 5 6 7 9 10 11 13 14 15 17 18 19 20
```
> *`continue` ne doit pas être confondu avec un retour prématuré de fonction ; il ne quitte que la boucle courante.*
---
## Synthèse du chapitre
- **Compilateur** : installer GCC (ou Clang), vérifier avec `--version`, compiler via `gcc -Wall -Wextra -o prog prog.c` et exécuter `./prog`.
- **Bibliothèque standard** : `<stdio.h>` pour `printf`, `scanf`, `puts`, `getchar` ; `<stdlib.h>` pour `malloc`, `free`.
- **Spécificateurs de conversion** : `%d`, `%ld`, `%f`, `%lf`, `%c`, `%s`, `%x`, `%%`.
- **Boucle `while`** : condition testée avant chaque itération ; utile quand le nombre d’itérations est inconnu.
- **Boucle `do‑while`** : corps exécuté au moins une fois ; condition testée après.
- **Boucle `for`** : initialisation ; condition ; mise à jour ; idéale pour un nombre connu d’itérations.
- **`break`** : sortie immédiate de la boucle.
- **`continue`** : passage à l’itération suivante.
- **Bonnes pratiques** : toujours tester le retour de `scanf`, activer les warnings (`-Wall -Wextra`), libérer la mémoire allouée avec `free`, éviter les débordements en choisissant des types adaptés (`unsigned long long` pour les factorielles).
---
## Glossaire
| Terme | Définition |
|-------|------------|
| **Compilateur** | Programme qui traduit le code source en langage machine exécutable. |
| **GCC** | GNU Compiler Collection, suite de compilateurs libres pour C, C++, etc. |
| **Bibliothèque standard** | Ensemble de fonctions pré‑compilées (ex. `printf`) accessibles via des en‑têtes `.h`. |
| **En‑tête** | Fichier `.h` contenant les déclarations (prototypes, macros) d’une bibliothèque. |
| **Spécificateur de conversion** | Séquence commençant par `%` dans une chaîne de format indiquant le type d’argument (`%d`, `%f`, …). |
| **Boucle while** | Structure de contrôle qui répète un bloc tant qu’une condition est vraie, testée avant l’exécution. |
| **Boucle do‑while** | Même principe que `while` mais la condition est évaluée après le corps, garantissant au moins une exécution. |
| **Boucle for** | Structure qui combine initialisation, test de condition et mise à jour en une ligne, adaptée aux comptages. |
| **break** | Instruction qui interrompt immédiatement l’exécution de la boucle la plus interne. |
| **continue** | Instruction qui saute le reste de l’itération en cours et passe à la suivante. |
| **EOF** | Macro (`End Of File`) renvoyée par les fonctions d’entrée lorsqu’aucune donnée n’est disponible. |
| **size_t** | Type entier non signé utilisé pour représenter la taille d’objets en mémoire (résultat de `sizeof`). |
| **malloc** | Fonction d’allocation dynamique de mémoire provenant de `<stdlib.h>`. |
| **free** | Fonction qui libère la mémoire précédemment allouée par `malloc`. |
| **unsigned long long** | Type entier non signé de 64 bits, capable de stocker des valeurs jusqu’à 2⁶⁴‑1. |
---
## Exercices d'application corrigés
### Exercice 1 – Installation et premier programme
**Consigne** : Installer GCC sur votre poste, créer un fichier `exo1.c` qui lit deux entiers `a` et `b` puis affiche leur somme, leur produit et la moyenne (en réel).
**Corrigé** :
```c
#include <stdio.h>
int main(void) {
int a, b;
printf("Entrez deux entiers séparés par un espace : ");
if (scanf("%d %d", &a, &b) != 2) {
printf("Saisie incorrecte.\n");
return 1;
}
int somme = a + b;
int produit = a * b;
double moyenne = (a + b) / 2.0; // conversion en double pour éviter la troncature
printf("Somme = %d\n", somme);
printf("Produit = %d\n", produit);
printf("Moyenne = %.2f\n", moyenne);
return 0;
}
```
**Étapes** :
1. Lecture sécurisée de deux entiers avec vérification du retour de `scanf`.
2. Calculs arithmétiques entiers pour la somme et le produit.
3. Conversion en `double` avant la division pour obtenir une moyenne réelle.
4. Affichage avec `printf` et spécificateurs `%d` et `%.2f`.
**Exemple d’exécution** :
```
Entrez deux entiers séparés par un espace : 7 3
Somme = 10
Produit = 21
Moyenne = 5.00
```
---
### Exercice 2 – Boucle while : table de multiplication
**Consigne** : Écrire un programme qui demande un entier `n` (1 ≤ n ≤ 12) et affiche la table de multiplication de `n` de 1 à 10 à l’aide d’une boucle `while`.
**Corrigé** :
```c
#include <stdio.h>
int main(void) {
int n;
do {
printf("Entrez n (1 à 12) : ");
scanf("%d", &n);
} while (n < 1 || n > 12);
int i = 1;
while (i <= 10) {
printf("%d x %d = %d\n", n, i, n * i);
++i;
}
return 0;
}
```
**Explication** :
- Boucle `do‑while` pour forcer une saisie dans l’intervalle autorisé.
- Initialisation `i = 1`, condition `i <= 10`, incrémentation `++i`.
- À chaque itération, affichage du produit `n * i`.
**Exemple** (`n = 4`) :
```
Entrez n (1 à 12) : 4
4 x 1 = 4
4 x 2 = 8
4 x 3 = 12
4 x 4 = 16
4 x 5 = 20
4 x 6 = 24
4 x 7 = 28
4 x 8 = 32
4 x 9 = 36
4 x 10 = 40
```
---
### Exercice 3 – Boucle for : recherche du maximum
**Consigne** : Lire 10 entiers saisis par l’utilisateur et déterminer la plus grande valeur à l’aide d’une boucle `for`. Afficher le maximum et son rang (première occurrence).
**Corrigé** :
```c
#include <stdio.h>
int main(void) {
int max, valeur, rang = 0; // rang commencera à 1 après la première lecture
printf("Entrez 10 entiers :\n");
for (int i = 0; i < 10; ++i) {
scanf("%d", &valeur);
if (i == 0 || valeur > max) {
max = valeur;
rang = i + 1; // rang humain (1‑based)
}
}
printf("Maximum = %d, rang = %d\n", max, rang);
return 0;
}
```
**Raisonnement** :
- À la première itération (`i == 0`) on initialise `max` avec la première valeur.
- Ensuite, chaque nouvelle valeur supérieure à `max` met à jour le maximum et enregistre son rang.
- Après la boucle, on affiche le résultat.
**Exemple** :
```
Entrez 10 entiers :
5 12 3 12 7 9 12 2 4 6
Maximum = 12, rang = 2
```
---
### Exercice 4 – Boucle do‑while : validation d’une note
**Consigne** : Demander à l’utilisateur de saisir une note comprise entre 0 et 20 (inclus). Redemander tant que la saisie est hors intervalle, puis afficher la mention selon le barème :
- `<10` : « Insuffisant »
- `10 ≤ note < 12` : « Passable »
- `12 ≤ note < 14` : « Assez bien »
- `14 ≤ note < 16` : « Bien »
- `≥16` : « Très bien »
**Corrigé** :
```c
#include <stdio.h>
int main(void) {
float note;
do {
printf("Entrez une note entre 0 et 20 : ");
scanf("%f", ¬e);
} while (note < 0.0f || note > 20.0f);
if (note < 10.0f)
printf("Mention : Insuffisant\n");
else if (note < 12.0f)
printf("Mention : Passable\n");
else if (note < 14.0f)
printf("Mention : Assez bien\n");
else if (note < 16.0f)
printf("Mention : Bien\n");
else
printf("Mention : Très bien\n");
return 0;
}
```
**Explication** :
- La boucle `do‑while` garantit au moins une demande de saisie.
- Après validation, une suite de `if … else if … else` détermine la tranche.
**Exemple** :
```
Entrez une note entre 0 et 20 : 25
Entrez une note entre 0 et 20 : -3
Entrez une note entre 0 et 20 : 13.5
Mention : Bien
```
---
### Exercice 5 – Imbrication de boucles : triangle de Pascal (niveau 5)
**Consigne** : Afficher les cinq premières lignes du triangle de Pascal. Chaque ligne `k` (en commençant par 0) contient les coefficients binomiaux C(k, i) pour `i = 0 … k`. Utiliser uniquement des boucles `for` et le calcul itératif du coefficient :
`C(k,0)=1` et `C(k,i)=C(k,i-1)*(k-i+1)/i`.
**Corrigé** :
```c
#include <stdio.h>
int main(void) {
const int n = 5; // nombre de lignes à afficher
for (int ligne = 0; ligne < n; ++ligne) {
// affichage des espaces pour centrer (optionnel)
for (int espace = 0; espace < n - ligne - 1; ++espace)
putchar(' ');
long long coeff = 1; // C(ligne,0)
for (int i = 0; i <= ligne; ++i) {
printf("%lld ", coeff);
// préparer le coefficient suivant
coeff = coeff * (ligne - i) / (i + 1);
}
putchar('\n');
}
return 0;
}
```
**Détail du calcul** :
- Au départ `coeff = 1` (C(k,0)).
- À chaque étape, on multiplie par `(ligne - i)` et on divise par `(i+1)` pour obtenir C(k,i+1).
- L’utilisation de `long long` évite les débordements pour les petites valeurs demandées.
**Exécution** :
```
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
```
---
## Erreurs fréquentes
| # | Erreur typique | Conséquence | Comment l’éviter |
|---|----------------|-------------|------------------|
| 1 | **Oublier le `&` devant une variable dans `scanf`** | `scanf` écrit à une adresse aléatoire → comportement indéfini, souvent un plantage. | Toujours précéder le nom de la variable par `&` sauf lorsqu’il s’agit d’un tableau (`char chaine[]`) où le nom se dégrade déjà en pointeur. |
| 2 | **Utiliser `%lf` avec `printf` pour afficher un `double`** | Dans `printf`, `%lf` est identique à `%f` mais certains compilateurs émettent un warning ; l’erreur vient plutôt de croire que la différence existe. | Utiliser `%f` pour `printf` (et `%lf` uniquement pour `scanf`). Se rappeler que la spécificateur de longueur n’a d’effet que dans les fonctions d’entrée. |
| 3 | **Confondre `while` et `do‑while`** | Une boucle `while` peut ne jamais s’exécuter si la condition est initialement fausse, alors que l’on voulait au moins une itération. | Analyser si le corps doit être exécuté au moins une fois ; si oui, privilégier `do‑while`. |
| 4 | **Débordement d’entier lors du calcul d’une factorielle** | Résultat incorrect ou comportement indéfini (wrap‑around). | Choisir un type suffisamment large (`unsigned long long` pour n ≤ 20) ou utiliser une bibliothèque d’arithmétique de grande précision si nécessaire. |
| 5 | **Ne pas libérer la mémoire allouée avec `malloc`** | Fuite de mémoire qui, dans des programmes longs, peut épuiser la ressource système. | Chaque appel à `malloc` doit être associé à un appel correspondant à `free` dès que la mémoire n’est plus nécessaire. |
| 6 | **Omettre le retour de `scanf` et traiter des données non initialisées** | Utilisation de variables contenant des valeurs aléatoires → résultats incohérents. | Toujours tester le retour de `scanf` (nombre d’éléments lus attendus) et gérer le cas d’échec (message d’erreur, nouvelle saisie, ou arrêt). |
---
*Fin du cours.*
Quiz du chapitre
10 questions — vérifie chaque réponse pour voir l'explication.