Accueil/Informatique & Développement /Chapitre 12 /Fiche de révision

Langage C

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

⚡ Le squelette, par cœur

C
#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é.

Trois règles de forme

  • Chaque instruction finit par ;
  • Chaque bloc tient entre { }
  • La casse compte : age ≠ Age, et Int n'existe pas

L'indentation ne fait pas la syntaxe — contrairement à Python.

Les types

TypeContenuTaille
intentier4 o
floatréel4 o
doubleréel précis8 o
charun caractère1 o
voidrien—

'A' = un caractère · "A" = une chaîne. const float PI = 3.14; fige la valeur.

⚡ printf lit · scanf écrit

C
printf("%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.

Codes de format

CodeTypeAffiche
%dint25
%ffloat1.750000
%.2ffloat1.75
%lfdouble15.567800
%cchara
%schaîneBonjour
%xhexadécimalff

\n saut de ligne · \t tabulation · %% un pourcent. Pour scanf(" %c", …), l'espace est obligatoire.

Opérateurs

+ - * / %arithmétique
== != < <= > >=comparaison
&& || !logiques — dans les if
& | ^ << >>bit à bit — masques
++ --incrément, décrément
c ? a : bternaire

a++ renvoie l'ancienne valeur, ++a la nouvelle.

Conditions

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

switch

C
switch (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.

Les trois boucles

C
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

Effetfor i 1→5, test sur 3
breakquitte la boucle1 2
continuesaute ce tour1 2 4 5

break = je quitte la salle · continue = je saute mon tour. goto existe : à savoir lire, à ne pas écrire.

⚡ Les huit pièges qui coûtent des points

  1. = affecte, == compare. if (a = 5) est toujours vrai et écrase a.
  2. 6 / 7 vaut 0 : entre entiers, division entière.
  3. for (…) ; — ce point-virgule vide la boucle.
  4. scanf sans & : compile parfois, plante à l'exécution.
  5. break oublié dans un switch : exécution en cascade.
  6. int somme; non initialisé : contient n'importe quoi. Écrire = 0.
  7. Code de format ≠ type de la variable : affichage aberrant, aucune alerte.
  8. Accolades omises : un if sans { } ne gouverne qu'une instruction, quelle que soit l'indentation.

Valeur du compteur à la sortie

ConditionÀ la sortie
i < 5i vaut 5
j <= 5j vaut 6

C'est la première valeur qui rend la condition fausse. Deux programmes du TP ne testent que cela.

Découper un entier

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

Compiler et lancer

terminal — macOS / Linux
cc programme.c -o programme
./programme

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

⚡ L'anatomie

type_retour nom(paramètres)
{ instructions ; return valeur ; }

Quatre éléments, toujours dans cet ordre. void quand il n'y a rien à rendre.

Définition → se termine par }, sans point-virgule.

Les quatre formes

sans retouravec 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 ≠ argument

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 prototype

int additionner(int a, int b);

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.

Portée des variables

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.

⚡ Les tableaux

float temperatures[7];

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.

⚡ Passer un tableau

float Moyenne(float t[], int n)

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.

Moyenne et maximum

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.

⚡ La division entière

(float) perdus / envoyes * 100

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.

⚡ Les fautes silencieuses

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.

Écrire une fonction, dans l'ordre

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.

Le TP 3, en un coup d'œil

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.

⚡ Adresse, pointeur, valeur

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

L'étoile a deux rôles

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.

Tableaux et pointeurs

C
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 pointe

Jamais 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é.

⚡ malloc · calloc · free

C
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;

La structure

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

Le point ou la flèche

Ce qu'on aOn écrit
une structure e1e1.age
un pointeur p dessusp->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.

Le & de scanf, enfin expliqué

scanf écrit dans la variable : il lui faut son adresse.

ChampSaisie
int, floatscanf("%d", &e1.age);
char[]scanf("%s", e1.nom); — déjà une adresse

Le TP 5, en un coup d'œil

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.

⚡ Les trois questions du TP 6

méthode
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.

Le TP 6, en un coup d'œil

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.

⚡ Les chaînes : un tableau, et une marque de fin

char mot[] = "Salut";
s a l u t \0 ← 6 cases pour 5 lettres

« 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".

Saisir : deux fonctions, deux comportements

scanf("%s", nom) ← s'arrête à l'espace
fgets(nom, 50, stdin) ← lit la ligne entière

Pas de & devant un tableau : il est déjà une adresse.

fgets garde le retour à la ligne dans la chaîne.

<string.h> — les quatre

strlen(ch) → longueur, sans le \0, en %zu
strcpy(dest, src) → remplace
strcat(dest, src) → ajoute à la fin
strcmp(a, b) → 0 si identiques

Aucune ne vérifie la taille de la destination.

⚠️ Le piège du zéro

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.