Des premiers concepts jusqu'au code de la factorielle
Laurent Thiry — Programmation en C
« Le C, c'est comme un couteau suisse : efficace, polyvalent,
et vous pouvez vous couper si vous ne faites pas attention. »
Info = contraction d'information et d'automatique
| Année | Quoi | Pourquoi c'est important |
|---|---|---|
| ~250 av. J.-C. | Algorithme d'Euclide (PGCD) | Un des plus vieux algorithmes encore utilisés |
| 1843 | Ada Lovelace — 1er programme | Avant même que la machine existe |
| 1936 | Turing — machine de Turing | Fonde théoriquement l'informatique. A aussi cassé Enigma. |
| 1945 | Von Neumann — architecture stockée | Programme et données dans la même mémoire |
| 1972 | Dennis Ritchie crée le C | Le langage de UNIX, Linux, Windows… et votre factorielle |
| 1980–90 | PC, Internet, Web | L'informatique sort des labos. |
1 bit → 2 valeurs 8 bits → 256 valeurs (0–255) 32 bits → 4 294 967 296 64 bits → 18 446 744 073 709 551 616
| Binaire | Décimal | Hexa |
|---|---|---|
| 0000 | 0 | 0x0 |
| 0101 | 5 | 0x5 |
| 1010 | 10 | 0xA |
| 1111 | 15 | 0xF |
| 1 0000 | 16 | 0x10 |
Bit de poids fort = signe (1 = négatif). Plage long long (64 bits) :
−9 223 372 036 854 775 808 à +9 223 372 036 854 775 807
20! = 2 432 902 008 176 640 000 tient encore.
21! dépasse — et le C ne vérifie pas.
Algorithme : suite finie d'instructions non-ambiguës qui, partant d'entrées, produit une sortie en temps fini.
// Algorithme : préparer un café (version express)
1. Remplir le réservoir d'eau
2. Mettre le café dans le filtre
3. Placer la tasse sous la sortie
4. Allumer la machine
5. Attendre que la tasse soit pleine
6. Servir
n! = 1 × 2 × 3 × … × n (avec 0! = 1)
Fonction factorielle(n):
Si n < 0 alors
retourner -1
Fin Si
res ← 1
Pour i ← 2 à n faire
res ← res × i
Fin Pour
retourner res
long long factorielle(int n) { if (n < 0) return -1; long long res = 1; for (int i = 2; i <= n; i++) { res *= i; } return res; }
Le C, créé par Dennis Ritchie en 1972 chez Bell Labs. Il a écrit UNIX, qui a écrit Linux, qui fait tourner Internet.
int main() { return 0; }
{ } délimitent un bloc; termine chaque instructionreturn 0; = tout va bien#include <stdio.h> int main() { printf("Bonjour les ingenieurs !\n"); return 0; }
#include insère un fichier d'en-tête\n = saut à la ligneUne variable est une boîte qui contient une valeur. Le type dit quelle sorte de valeur va dedans.
| Type | Taille | Exemple | Usage |
|---|---|---|---|
int | 32 bits | int n = 5; | Entier signé |
long long | 64 bits | long long x = 120LL; | Très grand entier |
float | 32 bits | float pi = 3.14f; | Virgule simple précision |
double | 64 bits | double pi = 3.14159; | Virgule double précision |
char | 8 bits | char c = 'A'; | Un caractère |
%d → int · %lld → long long · %f → double · %c → char · %s → chaîne · %x → hexa
long long prennent un suffixe LL : 2432902008176640000LL.| Op | Opération | Exemple | = |
|---|---|---|---|
+ | Addition | 10+3 | 13 |
- | Soustraction | 10-3 | 7 |
* | Multiplication | 10*3 | 30 |
/ | Division entière | 10/3 | 3 |
% | Modulo | 10%3 | 1 |
| Op | Vrai si… |
|---|---|
== | égal à |
!= | différent de |
< > | plus petit/grand |
&& | ET (court-circuit) |
|| | OU (court-circuit) |
! | NON |
= (affectation) ≠ == (comparaison). if (n = 5) est toujours vrai. Activez -Wall.&& et || sont paresseux : si la première partie suffit, la seconde n'est pas évaluée. C'est la flemme au niveau processeur.if (n < 0) { return -1; } else { // calcul }
for (int i = 2; i <= n; i++) { res *= i; }
init ; condition ; incrément
int i = 2; while (i <= n) { res *= i; i++; }
// Parcourir un tableau for (int i = 0; i < n; i++) // Compter a rebours for (int i = n; i > 0; i--) // Pas de 2 for (int i = 0; i < 100; i += 2)
for = tour de manège (nombre de tours connu). while = attente du bus (on ne sait pas quand il arrive). Les deux font la même chose, mais le bon rend le code lisible.Fonction : boîte noire qui prend des paramètres et produit une valeur de retour.
int main() { int n = 5; long long res = 1; for (int i = 2; i <= n; i++) res *= i; printf("%lld\n", res); return 0; }
long long factorielle(int n) { long long res = 1; for (int i = 2; i <= n; i++) res *= i; return res; } int main() { printf("%lld\n", factorielle(5)); return 0; }
long long factorielle(int n) { if (n < 0) return -1; long long res = 1; for (int i = 2; i <= n; i++) { res *= i; } return res; }
| Entrée | Déroulement | Sortie |
|---|---|---|
| n = 0 | boucle non exécutée (2 ≤ 0 faux) | 1 |
| n = 1 | boucle non exécutée (2 ≤ 1 faux) | 1 |
| n = 5 | 1×2×3×4×5 | 120 |
| n = −3 | return -1 immédiat | −1 |
long long fact_rec(int n) { if (n < 0) return -1; if (n <= 1) return 1; return n * fact_rec(n - 1); }
Élégante, risque de pile pour n grand
long long fact_while(int n) { if (n < 0) return -1; long long res = 1; int i = 2; while (i <= n) { res *= i; i++; } return res; }
long long fact_desc(int n) { if (n < 0) return -1; long long res = 1; for (int i = n; i > 1; i--) res *= i; return res; }
Un programme non testé est un programme qui a tort — mais qui ne le sait pas encore.
| Type de test | Exemple |
|---|---|
| Cas nominal | factorielle(5) → 120 |
| Cas limite | factorielle(0) → 1, factorielle(20) → 20! |
| Cas d'erreur | factorielle(-1) → -1 |
| Dépassement | factorielle(21) → overflow silencieux |
struct { int n; long long attendu; } tests[] = { {0, 1}, {1, 1}, {2, 2}, {3, 6}, {5, 120}, {10, 3628800}, {12, 479001600}, {20, 2432902008176640000LL}, }; int nb_tests = sizeof(tests) / sizeof(tests[0]);
| Étape | Fait | Commande | Fichier |
|---|---|---|---|
| 1. Préprocesseur | Remplace #include, #define | gcc -E | — |
| 2. Compilation | C → assembleur | gcc -S | .s |
| 3. Assemblage | assembleur → machine | gcc -c | .o |
| 4. Édition de liens | .o + biblio → exécutable | gcc | factorielle |
-Wall comme vous lavez les légumes.while au lieu de for. Vérifiez que les résultats sont identiques.n | n! | OK/FAIL. Utilisez %10d et %20lld pour aligner.long long somme(int n) qui calcule 1+2+…+n avec une boucle. Comparez avec la formule n(n+1)/2.long long C(int n, int k) qui calcule C(n,k) = n! / (k! (n-k)!) en utilisant factorielle. Testez avec C(5,2) = 10. Évitez l'overflow en simplifiant avant de multiplier.scanf. Bouclez jusqu'à ce que l'utilisateur entre une valeur négative. Ajoutez un message d'erreur si n > 20.
Vous savez ce qu'est un algorithme, un bit, une variable,
une boucle, une fonction, un compilateur —
et pourquoi votre café refroidit pendant que vous codez.
make && make run