⚡ Le squelette, par cœur
#include <stdio.h>
int main()
{
int age = 20;
printf("%d\n", age);
return 0;
}#include donne printf/scanf ·
l'exécution commence à main · return 0 = tout s'est bien passé.
Les trois séances sur une seule fiche : le langage, les fonctions et les tableaux, puis les pointeurs, la mémoire dynamique et les structures. À relire la veille. Le cours · Les exercices
#include <stdio.h>
int main()
{
int age = 20;
printf("%d\n", age);
return 0;
}#include donne printf/scanf ·
l'exécution commence à main · return 0 = tout s'est bien passé.
;{ }age ≠ Age,
et Int n'existe pasL'indentation ne fait pas la syntaxe — contrairement à Python.
| Type | Contenu | Taille |
|---|---|---|
int | entier | 4 o |
float | réel | 4 o |
double | réel précis | 8 o |
char | un caractère | 1 o |
void | rien | — |
'A' = un caractère · "A" = une chaîne.
const float PI = 3.14; fige la valeur.
printf lit · scanf écritprintf("%d\n", age); /* pas de & */
scanf("%d", &age); /* & OBLIGATOIRE */scanf doit ranger quelque chose dans la variable : elle a
besoin de son adresse, pas de son contenu. On donne l'adresse de la boîte
aux lettres, pas ce qu'il y a dedans.
| Code | Type | Affiche |
|---|---|---|
%d | int | 25 |
%f | float | 1.750000 |
%.2f | float | 1.75 |
%lf | double | 15.567800 |
%c | char | a |
%s | chaîne | Bonjour |
%x | hexadécimal | ff |
\n saut de ligne · \t tabulation · %% un pourcent.
Pour scanf(" %c", …), l'espace est obligatoire.
+ - * / % | arithmétique |
== != < <= > >= | comparaison |
&& || ! | logiques — dans les if |
& | ^ << >> | bit à bit — masques |
++ -- | incrément, décrément |
c ? a : b | ternaire |
a++ renvoie l'ancienne valeur, ++a la
nouvelle.
if (n > 0) {
printf("positif\n");
} else if (n < 0) {
printf("negatif\n");
} else {
printf("nul\n");
}Intervalle → if…else if.
Liste de valeurs → switch.
switchswitch (choix) {
case 1:
printf("un\n");
break;
case 'o':
case 'O':
printf("oui\n");
break;
default:
printf("autre\n");
}Un break par case, sinon l'exécution continue
en cascade. Deux case collés = regroupement volontaire.
while (i <= 5) { … } /* 0 tour possible */
do { … } while (i <= 5); /* 1 tour minimum */
for (i = 1; i <= 5; i++) { … }Nombre de tours connu → for ·
au moins un passage (saisie à valider) → do…while ·
sinon while.
Le ; final de do…while est obligatoire.
break · continue| Effet | for i 1→5, test sur 3 | |
|---|---|---|
break | quitte la boucle | 1 2 |
continue | saute ce tour | 1 2 4 5 |
break = je quitte la salle · continue = je saute mon tour.
goto existe : à savoir lire, à ne pas écrire.
= affecte, == compare. if (a = 5) est
toujours vrai et écrase a.6 / 7 vaut 0 : entre entiers, division entière.for (…) ; — ce point-virgule vide la boucle.scanf sans & : compile parfois, plante à l'exécution.break oublié dans un switch : exécution en cascade.int somme; non initialisé : contient n'importe quoi. Écrire
= 0.if sans { } ne gouverne
qu'une instruction, quelle que soit l'indentation.| Condition | À la sortie |
|---|---|
i < 5 | i vaut 5 |
j <= 5 | j vaut 6 |
C'est la première valeur qui rend la condition fausse. Deux programmes du TP ne testent que cela.
n % 10 /* dernier chiffre */
n / 10 /* retire ce chiffre */
(n / 10) % 10 /* chiffre des dizaines */Ces deux opérations suffisent à inverser un nombre, compter ses chiffres ou les permuter — exercices 4 et 7.
cc programme.c -o programme
./programmeSur le poste : Code::Blocks (MinGW). Sans rien installer : un compilateur C en ligne.
Erreur de compilation = le programme n'existe pas · erreur d'exécution = il tourne mais se trompe. Lire la première erreur, pas la dernière.
Quatre éléments, toujours dans cet ordre. void quand il
n'y a rien à rendre.
Définition → se termine par }, sans point-virgule.
| sans retour | avec retour | |
|---|---|---|
| sans par. | void f() | int f() |
| avec par. | void f(int n) | int f(int n) |
Deux questions indépendantes : reçoit-elle ? et rend-elle ?
Paramètre — la variable de la définition.
Argument — la valeur de l'appel.
int additionner(int a, int b) → a, b paramètres
additionner(10, 20); → 10, 20 arguments
Le paramètre est le contenant, l'argument le contenu.
Le point-virgule est ce qui le distingue d'une définition.
Il permet d'écrire main en premier. Sans prototype, la définition doit
précéder l'appel.
C'est exactement ce que contient <stdio.h> : le prototype de
printf, pas son code.
Locale — déclarée dans une fonction, n'existe que là, disparaît à la sortie.
Globale — déclarée hors de toute fonction, visible partout.
Bonne pratique : locale par défaut, et on passe ce dont la fonction a besoin en paramètre. Une fonction qui reçoit tout se lit seule et se réutilise.
Indices de 0 à taille − 1. La boucle s'écrit i < n,
jamais i <= n.
Saisie : scanf("%f", &t[i]); — le & ne disparaît pas.
Le C ne vérifie aucun indice. Sortir du tableau ne provoque aucune erreur : juste un bogue, plus tard.
Un tableau passé perd sa taille. sizeof y rend 8 — la
taille d'une adresse — et non 40.
Donc : toujours n en second paramètre.
En échange, la fonction reçoit l'adresse : elle peut remplir le
tableau. C'est pour ça que SaisirTableau() ne retourne rien.
somme = 0.0f; avant la boucle — toujours initialiser.
max = t[0]; puis boucle i = 1.
Partir de max = 0 est faux dès qu'une valeur est négative : on
renverrait 0, qui n'est pas dans le tableau.
Deux int divisés donnent un int : 25 / 500 vaut
0.
Ça compile, ça tourne, et ça affiche 0.00 %.
Autre écriture juste : perdus * 100.0 / envoyes.
La casse. afficherCarre ≠ affichercarre.
Deux exemples du polycopié ne compilent pas pour ça.
0 <= v <= 255 compile et est toujours vraie.
Il faut 0 <= v && v <= 255.
carre(4); seul — le résultat part à la poubelle.
(a + b) / 2 — sans parenthèses, la division passe
avant.
%% pour afficher un pourcentage.
1. de quoi a-t-elle besoin ? → les paramètres
2. rend-elle une valeur ? → le type, ou void
3. le corps — une seule tâche
4. l'appel — où ranger le résultat ?
Le test : une fonction se décrit en une phrase sans « et ». S'il y a un « et », il y a deux fonctions.
1–4 fonctions simples : moyenne, octet IPv4 valide, débit, taux de perte.
5–7 tableaux : 7 températures, 8 débits, recherche dans 10 valeurs.
8–9 découpage : CPU en 4 fonctions, notes en 5.
Résultats à retrouver : 20.00 · 12.00 Mo/s ·
5.00 % · 22.4 °C · 102.88 Mb/s ·
58.40 % · 11.50 et 7 admis.
int age = 20;
int *p = &age; /* p contient l'ADRESSE de age */
age -> 20 la valeur
&age -> 0x7ffd... l'adresse
p -> 0x7ffd... la meme adresse
*p -> 20 la valeur, atteinte par p& = « où ? » · * = « quoi ? ». Les deux se défont :
*(&age), c'est age.
int *p; — déclaration : « p est un pointeur ».
*p = 30; — opérateur : « va à l'adresse rangée dans p ».
Pour les distinguer : y a-t-il un type devant ? Si oui, c'est une déclaration.
p = 30; ≠ *p = 30; — le premier change l'adresse, le second
la valeur pointée.
tab == &tab[0] le nom d'un tableau EST une adresse
p[i] == *(p + i) deux ecritures, une seule notion
p++ avance d'UNE CASE du type pointeJamais les deux à la fois : p[i]
avec p++ lit tab[2i] — une case sur deux, puis hors du
tableau.
Un tableau n'est pas une variable : tab++ est refusé.
p = malloc(n * sizeof(int)); /* n cases, contenu indetermine */
q = calloc(n, sizeof(int)); /* n cases, toutes a ZERO */
if (p == NULL) return 1; /* TOUJOURS */
...
free(p); /* TOUJOURS */#include <stdlib.h> · on compte en octets, d'où
sizeof · jamais un nombre écrit en dur.
Oublier free → fuite · free deux fois → plantage ·
utiliser après free → pointeur fou. Réflexe :
free(p); p = NULL;
struct Etudiant {
char nom[30];
int age;
float moyenne;
}; /* ; OBLIGATOIRE */
struct Etudiant e1 = {"Alice", 20, 15.5};
e1.age = 21;
strcpy(e1.nom, "Bilal"); /* jamais e1.nom = "..." */Définir un struct ne crée aucune variable : c'est un moule.
| Ce qu'on a | On écrit |
|---|---|
une structure e1 | e1.age |
un pointeur p dessus | p->age |
p->age est exactement (*p).age.
Dans une fonction : par valeur → copie, l'original ne bouge pas ·
par adresse (struct Etudiant *e, appel
f(&e1)) → on modifie pour de bon.
& de scanf, enfin expliquéscanf écrit dans la variable : il lui faut son adresse.
| Champ | Saisie |
|---|---|
int, float | scanf("%d", &e1.age); |
char[] | scanf("%s", e1.nom); — déjà une adresse |
1 huit mesures parcourues au pointeur · 2 saisie de
taille inconnue, malloc · 3 recherche et position ·
4 capteur, calloc et contrôle de l'allocation.
Résultats à retrouver : somme 122, max 25 · somme
62, moyenne 15.50 · position 3 · moyenne
19.12, min 17.00, max 21.25.
1. La fonction LIT ou ECRIT ?
lit -> struct X v acces v.champ appel f(v)
ecrit -> struct X *v acces v->champ appel f(&v)
2. Le nombre est-il connu a l'avance ?
oui -> struct X t[5];
non -> malloc(n * sizeof(struct X)) ... free(t);
3. Le champ est-il une CHAINE ?
oui -> strcpy(v.nom, "...") scanf("%29s", v.nom) sans &
non -> v.age = 20 scanf("%d", &v.age) avec &Sept exercices, et rien d'autre à savoir que de répondre juste à ces trois questions.
1 un produit · 2 un véhicule, champ mis à jour · 3 tableau de 5 · 4 saisir / afficher en fonctions · 5 un capteur au pointeur · 6 bibliothèque allouée · 7 structure imbriquée.
Résultats à retrouver : 468.00 · 91200 km ·
1840.75 · 980.00 · dépassement 1.40 ·
moyenne 41.83 (3 livres) · 15/09/2026.
%02d donne 09, %-14s aligne à gauche,
%29s protège un champ de 30.
« 49 caractères maximum » → char mot[50] : toujours une
case de plus pour le '\0'.
%s pour une chaîne, %c pour un caractère.
'A' ≠ "A".
Pas de & devant un tableau : il est déjà une adresse.
fgets garde le retour à la ligne dans la chaîne.
Aucune ne vérifie la taille de la destination.
strcmp(a, b) == 0 veut dire identiques — l'inverse de la
convention habituelle où 0 est faux.
Et la valeur non nulle n'est pas portable : seul son signe l'est. On
teste < 0, == 0, > 0 — jamais
== -1.