Accueil/Informatique & Développement /Chapitre 12 /Exercices corrigés

Langage C — exercices

Les huit exercices du TP2 — le langage, jusqu'aux boucles — puis les dix du TP3, sur les fonctions et les tableaux. Chaque correction a été compilée puis exécutée avant d'être écrite ici, et recompilée à chaque mise à jour de ce site.

🎯 Comment travailler ce chapitre

Le C ne s'apprend pas en lisant. Ouvrez un compilateur — en ligne sur onlinegdb.com, ou Code::Blocks sur le poste — et tapez chaque programme. Vous ferez des erreurs de compilation : c'est le but. Apprendre à lire un message d'erreur est la moitié du métier.

Cherchez d'abord seul, au moins dix minutes. La correction ne vaut que si vous savez ce que vous n'avez pas trouvé.

01TP 2 · Appréciation d'une note

1Note sur 20 → appréciation Facile

Demander une note sur 20 et afficher une appréciation :

NoteAppréciation
note < 10Insuffisant
10 ⩽ note < 12Passable
12 ⩽ note < 14Assez bien
14 ⩽ note < 16Bien
note ⩾ 16Très bien

Le programme doit aussi vérifier que la note est comprise entre 0 et 20. Sinon, afficher Note invalide.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    float note;

    printf("Entrez une note sur 20 : ");
    scanf("%f", &note);

    if (note < 0 || note > 20) {
        printf("Note invalide\n");
    } else if (note < 10) {
        printf("Insuffisant\n");
    } else if (note < 12) {
        printf("Passable\n");
    } else if (note < 14) {
        printf("Assez bien\n");
    } else if (note < 16) {
        printf("Bien\n");
    } else {
        printf("Tres bien\n");
    }
    return 0;
}
🧰 Pourquoi else if et pas cinq if séparés

Avec une chaîne else if, dès qu'une condition est vraie toutes les suivantes sont ignorées. C'est ce qui permet d'écrire note < 12 tout court : on sait déjà qu'elle n'est pas inférieure à 10, puisque la branche précédente n'a pas été prise.

Avec cinq if indépendants, il faudrait écrire if (note >= 10 && note < 12) — plus long, et plus facile à rater.

Une chaîne else if se lit comme un escalier : on descend jusqu'à la première marche qui tient.

⚠️ Le test de validité doit venir EN PREMIER

Si l'on place if (note < 0 || note > 20) en dernier, il ne sera jamais atteint : une note de 25 aurait déjà déclenché note >= 16 → Très bien. Une note de −5 aurait déclenché note < 10 → Insuffisant.

Dans une chaîne else if, l'ordre est la logique. Le cas d'erreur se teste avant les cas normaux.

💡 float plutôt que int

Une note peut valoir 12,5. Avec int note;, scanf("%d", …) lirait 12 et laisserait ,5 dans le tampon — la suite du programme partirait en vrille. Le type doit correspondre à la réalité de la donnée, pas à ce qui est le plus simple à écrire.

Vérifié à l'exécution pour 8 → Insuffisant, 11 → Passable, 13 → Assez bien, 15 → Bien, 18 → Très bien, 25 → Note invalide.

02TP 2 · Somme de 1 à N

2Accumuler dans une boucle Facile

Demander un entier N puis calculer la somme des nombres de 1 à N.

exemple attendu
N = 5
1 + 2 + 3 + 4 + 5 = 15
✅ Correction
C
#include <stdio.h>

int main(void)
{
    int n, i, somme = 0;

    printf("Entrez N : ");
    scanf("%d", &n);

    for (i = 1; i <= n; i++) {
        somme = somme + i;
    }

    printf("La somme de 1 a %d vaut %d\n", n, somme);
    return 0;
}
⚠️ int somme = 0; — le = 0 n'est pas décoratif

Écrire int somme; puis somme = somme + i; additionne à une valeur inconnue : celle qui traînait en mémoire. Le programme compile, tourne, et donne un résultat différent d'une exécution à l'autre.

C'est le réflexe à prendre : tout accumulateur s'initialise. À 0 pour une somme, à 1 pour un produit.

🧰 La vérification qui ne coûte rien

Gauss a montré que la somme de 1 à n vaut n × (n + 1) / 2. Pour n = 5 : 5 × 6 / 2 = 15 ✔

Un test rapide de votre programme : si la boucle et la formule ne donnent pas la même chose, c'est la boucle qui a tort.

C — contrôle
printf("controle : %d\n", n * (n + 1) / 2);

Vérifié à l'exécution : N = 5 donne bien 15.

03TP 2 · Menu de gestion du serveur

3Un menu avec switch Facile

Afficher le menu suivant, lire un choix entre 1 et 5, et réagir en conséquence.

affichage attendu
===== GESTION DU SERVEUR =====
1. Démarrer le serveur
2. Arrêter le serveur
3. Redémarrer le serveur
4. Afficher l'état du serveur
5. Quitter

Votre choix :

1 → Le serveur démarre… · 2 → Le serveur s'arrête… · 3 → Le serveur redémarre… · 4 → État du serveur : ACTIF · 5 → Au revoir · tout autre choix → Choix invalide.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    int choix;

    printf("===== GESTION DU SERVEUR =====\n");
    printf("1. Demarrer le serveur\n");
    printf("2. Arreter le serveur\n");
    printf("3. Redemarrer le serveur\n");
    printf("4. Afficher l'etat du serveur\n");
    printf("5. Quitter\n\n");
    printf("Votre choix : ");
    scanf("%d", &choix);

    switch (choix) {
        case 1: printf("Le serveur demarre...\n");    break;
        case 2: printf("Le serveur s'arrete...\n");   break;
        case 3: printf("Le serveur redemarre...\n");  break;
        case 4: printf("Etat du serveur : ACTIF\n");  break;
        case 5: printf("Au revoir\n");                break;
        default: printf("Choix invalide\n");
    }
    return 0;
}
⚠️ Enlevez un break et observez

Supprimez celui du case 1 puis choisissez 1 : le programme affiche Le serveur démarre… puis Le serveur s'arrête… Il ne s'arrête qu'au premier break rencontré.

Faites l'expérience une fois : vous n'oublierez plus jamais de break.

🧰 Les accents dans un terminal

La correction écrit Demarrer sans accent. Ce n'est pas de la négligence : selon l'encodage de la console — surtout sous Windows — un é peut s'afficher é. Tant que l'encodage n'est pas maîtrisé, mieux vaut un texte sans accent qu'un affichage illisible.

Dans le rendu de votre TP, gardez les accents de l'énoncé et signalez ce point : cela montre que vous l'avez compris.

💡 Aller plus loin : redemander tant que le choix est invalide

Un vrai menu ne s'arrête pas après un mauvais choix. C'est exactement le cas d'usage du do…while :

C
do {
    printf("Votre choix : ");
    scanf("%d", &choix);
} while (choix < 1 || choix > 5);

Il faut au moins une saisie : la condition se teste donc après.

Vérifié à l'exécution : 1 → Le serveur démarre…, 4 → État du serveur : ACTIF, 9 → Choix invalide.

04TP 2 · Nombre inversé

4Retourner un entier Moyen

Demander un entier positif et afficher ce nombre à l'envers. Si le nombre n'est pas positif, afficher Erreur : le nombre doit être positif.

exemple attendu
Entrez un nombre : 12345
Nombre inversé : 54321
✅ Correction
C
#include <stdio.h>

int main(void)
{
    int nombre, inverse = 0, chiffre;

    printf("Entrez un nombre : ");
    scanf("%d", &nombre);

    if (nombre <= 0) {
        printf("Erreur : le nombre doit etre positif.\n");
        return 0;
    }

    while (nombre > 0) {
        chiffre = nombre % 10;            /* le dernier chiffre */
        inverse = inverse * 10 + chiffre; /* on le pousse à gauche */
        nombre  = nombre / 10;            /* on le retire du nombre */
    }

    printf("Nombre inverse : %d\n", inverse);
    return 0;
}
🔍 Le mécanisme : dépiler d'un côté, empiler de l'autre

Deux opérations font tout le travail, et ce sont exactement celles du chapitre d'arithmétique de 1re année :

  • nombre % 10 donne le dernier chiffre (le reste de la division par 10) ;
  • nombre / 10 retire ce dernier chiffre (division entière).

Et inverse * 10 + chiffre décale ce qu'on a déjà d'un cran vers la gauche pour faire de la place au nouveau chiffre.

Tournombrechiffreinverse
départ12345—0
1123455
2123454
3123543
4125432
50154321

Quand nombre atteint 0, la condition devient fausse et la boucle s'arrête d'elle-même. On n'a jamais eu besoin de compter les chiffres.

⚠️ Pourquoi while et non for

On ne sait pas combien de chiffres contient le nombre — c'est justement ce qu'on refuse de compter. Le nombre de tours est donc inconnu : c'est la définition même du while.

« Combien de tours ? » est toujours la bonne question pour choisir sa boucle.

Vérifié à l'exécution : 12345 → 54321, et −3 → le message d'erreur.

05TP 2 · Le jeu du nombre caché

5Deviner, avec compteur de coups Moyen

Le premier joueur saisit un entier ; le second doit le deviner, avec autant de tentatives qu'il le souhaite. Après chaque échec, indiquer si le nombre cherché est plus grand ou plus petit. Compter les tentatives et afficher le score à la fin.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    int secret, proposition, tentatives = 0;

    printf("Joueur 1, entrez le nombre a deviner : ");
    scanf("%d", &secret);

    do {
        printf("Proposition : ");
        scanf("%d", &proposition);
        tentatives++;

        if (proposition < secret) {
            printf("  C'est plus grand.\n");
        } else if (proposition > secret) {
            printf("  C'est plus petit.\n");
        }
    } while (proposition != secret);

    printf("Bravo ! Trouve en %d coup(s).\n", tentatives);
    return 0;
}
🧰 Trois décisions qui font tout l'exercice
  • do…while — il faut au moins une proposition avant de pouvoir la comparer. Avec un while, il faudrait une première saisie en dehors de la boucle : deux fois le même code.
  • Pas de else pour le cas gagnant — quand la proposition est juste, aucun des deux messages ne s'affiche, et la condition de boucle suffit à sortir.
  • tentatives++ dans la boucle, juste après la saisie : on compte ce qui a été joué, y compris le coup gagnant.
⚠️ « Plus grand » : plus grand que quoi ?

Si la proposition est inférieure au secret, c'est le nombre à trouver qui est plus grand. La tentation est d'écrire « C'est plus petit » parce qu'on pense à la proposition.

Le message doit parler du nombre cherché, pas de la proposition. Faites l'essai avec un nombre connu : on s'en rend compte tout de suite.

💡 Faire tirer le nombre par l'ordinateur
C
#include <stdlib.h>
#include <time.h>

srand(time(NULL));              /* une seule fois, au début */
int secret = rand() % 100 + 1;  /* entre 1 et 100 */

Sans srand(time(NULL)), rand() donne la même suite à chaque lancement : le secret serait toujours le même.

Vérifié à l'exécution : secret 42, propositions 50 puis 30 puis 42 → « plus petit », « plus grand », « Trouvé en 3 coup(s) ».

06TP 2 · Nombre presque parfait

6Somme des diviseurs propres Moyen

Un nombre presque parfait est un entier naturel dont la somme des diviseurs — lui-même exclu — est inférieure de 1 à lui-même.

Exemple : 16 est presque parfait, car 1 + 2 + 4 + 8 = 15 = 16 − 1.

Écrire un programme qui demande un nombre et dit s'il est presque parfait.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    int n, i, somme = 0;

    printf("Entrez un nombre : ");
    scanf("%d", &n);

    for (i = 1; i < n; i++) {      /* i < n : on exclut n lui-même */
        if (n % i == 0) {
            somme = somme + i;
        }
    }

    printf("Somme des diviseurs propres : %d\n", somme);

    if (somme == n - 1) {
        printf("%d est presque parfait.\n", n);
    } else {
        printf("%d n'est pas presque parfait.\n", n);
    }
    return 0;
}
🧰 Traduire l'énoncé, mot à mot
L'énoncé dit……qui s'écrit
« i divise n »n % i == 0
« hormis lui-même »i < n, et non i <= n
« inférieure de 1 à lui-même »somme == n - 1

Un énoncé de maths se traduit ligne par ligne. Quand on bloque, c'est presque toujours qu'une phrase n'a pas été traduite.

💡 Les presque parfaits sont les puissances de 2

Testez 8 : 1 + 2 + 4 = 7 = 8 − 1 ✔. Puis 32 : 1 + 2 + 4 + 8 + 16 = 31 ✔. Puis 12 : 1 + 2 + 3 + 4 + 6 = 16, ce qui fait 4 de trop ✘.

Les diviseurs propres de 2k sont exactement 1, 2, 4, …, 2k−1, et leur somme vaut 2k − 1. Aucun autre nombre presque parfait n'est connu.

Un bon jeu de tests : 8 et 16 doivent répondre oui, 12 doit répondre non.

⚠️ i <= n casserait tout

Avec i <= n, la somme inclurait n lui-même : pour 16 elle vaudrait 31 au lieu de 15, et aucun nombre ne serait jamais déclaré presque parfait. Le programme tournerait sans erreur et répondrait toujours non.

Le pire des bugs : celui qui donne une réponse plausible.

Vérifié à l'exécution : 16 → presque parfait, 8 → presque parfait, 12 → ne l'est pas.

07TP 2 · Les nombres formés par trois chiffres

7Les six permutations Difficile

Saisir un entier de trois chiffres non nuls, puis afficher tous les nombres que l'on peut former avec ces chiffres.

exemple attendu
N = 578
Les nombres formés par les chiffres de N sont : 578, 587, 785, 758, 857, 875.
✅ Correction
C
#include <stdio.h>

int main(void)
{
    int n, c1, c2, c3;

    printf("Entrez un entier de trois chiffres non nuls : ");
    scanf("%d", &n);

    if (n < 100 || n > 999) {
        printf("Erreur : il faut trois chiffres.\n");
        return 0;
    }

    c1 = n / 100;          /* centaines */
    c2 = (n / 10) % 10;    /* dizaines  */
    c3 = n % 10;           /* unités    */

    if (c1 == 0 || c2 == 0 || c3 == 0) {
        printf("Erreur : les trois chiffres doivent etre non nuls.\n");
        return 0;
    }

    printf("%d %d %d %d %d %d\n",
           c1*100 + c2*10 + c3,  c1*100 + c3*10 + c2,
           c2*100 + c1*10 + c3,  c2*100 + c3*10 + c1,
           c3*100 + c1*10 + c2,  c3*100 + c2*10 + c1);
    return 0;
}
🧰 Extraire les trois chiffres
ChiffreCalculSur 578
centainesn / 100578 / 100 = 5
dizaines(n / 10) % 1057 % 10 = 7
unitésn % 10578 % 10 = 8

Là encore, / et % sur des entiers : les deux seules opérations dont on a besoin pour découper un nombre.

💡 Pourquoi exactement six, et pourquoi « non nuls »

Trois chiffres distincts donnent 3 × 2 × 1 = 6 arrangements : trois choix pour la position des centaines, deux pour celle des dizaines, un pour le reste.

La condition « non nuls » de l'énoncé s'explique ainsi : avec un 0 — disons 508 — la permutation 085 ne serait plus un nombre de trois chiffres, elle vaudrait 85. La règle évite ce cas particulier.

Si les chiffres se répètent (515), les six résultats contiennent des doublons. L'énoncé ne l'interdit pas ; on peut le signaler dans le compte rendu.

⚠️ L'ordre d'affichage n'est pas celui de l'énoncé

Ce programme affiche 578 587 758 785 857 875 ; l'énoncé annonce 578, 587, 785, 758, 857, 875. Les six nombres sont les mêmes — seul l'ordre diffère, et l'énoncé ne fixe aucun ordre.

Avant de croire à une erreur, comparez les ensembles. Ici tout est juste.

Vérifié à l'exécution : 578 donne bien ces six nombres.

08TP 2 · Six programmes à tracer

« Que vont afficher les programmes suivants ? » L'exercice le plus formateur du TP : il ne demande pas d'écrire du code, mais de le lire exactement. Les six résultats ci-dessous ont été obtenus en compilant et en exécutant chaque programme.

🔧 Corrigé — main() sans type ne compile plus

Les six programmes de l'énoncé commencent par main(), sans int. C'était légal dans le C des origines : le type int était sous-entendu. Depuis la norme C99, ce n'est plus accepté — un compilateur d'aujourd'hui refuse les six programmes tels qu'imprimés :

message du compilateur
error: type specifier missing, defaults to 'int';
       ISO C99 and later do not support implicit int

Il manque aussi #include <stdio.h>, sans quoi printf n'est pas déclarée. La diapositive « Structure simplifiée d'un programme C » écrit d'ailleurs correctement int main() : c'est l'énoncé du TP qui n'a pas suivi.

Les corrections ci-dessous rétablissent #include et int main(). Rien d'autre n'a été touché : les pièges restent entiers.

①Le point-virgule qui vide la boucle Moyen

C
#include <stdio.h>
int main()
{ int n=5, i;
    for(i=2; i<n; i++);
    printf("%d\n",i);
}
✅ Correction
sortie réelle
5

Le ; juste après for(...) est le corps de la boucle : un corps vide. La boucle se contente donc de faire monter i de 2 à 5, puis s'arrête quand i < 5 devient faux.

Le printf, qui n'a jamais appartenu à la boucle, s'exécute une seule fois et affiche la valeur de sortie : 5.

⚠️ Sans ce point-virgule, la réponse serait 2 3 4

C'est toute la différence entre « la boucle affiche » et « la boucle compte, puis on affiche ». Un caractère.

②Division entre entiers Facile

C
#include <stdio.h>
int main()
{  int n=6, m=7;
   printf("%d", n/m);
}
✅ Correction
sortie réelle
0

6 / 7 vaudrait 0,857… mais n et m sont deux int : la division est entière. Le quotient est 0, la partie décimale est jetée — pas arrondie.

Noter aussi l'absence de \n : la sortie ne passe pas à la ligne.

🧰 Obtenir 0.857143
C
printf("%f", (float) n / m);   /* on convertit, puis on divise */

Il suffit qu'une des deux valeurs soit réelle pour que la division le devienne.

③Une boucle sans incrément Difficile

C
#include <stdio.h>
int main()
{ int m=18, j, verif=0;
   for(j=2; !verif;)
   if(j==5)
   verif=18;
   else
   printf("%d\n", ++j);
}
✅ Correction
sortie réelle
3
4
5

Trois choses à démêler :

  • La partie « modification » du for est vide — for(j=2; !verif;). Ce n'est pas une boucle infinie pour autant : c'est le ++j du printf qui fait avancer j.
  • !verif est la condition : « tant que verif vaut 0 ». Mettre verif = 18 la rend fausse et arrête la boucle. La valeur 18 n'a aucune importance — seul compte qu'elle soit non nulle.
  • ++j incrémente AVANT d'afficher : au premier tour j vaut 2, et c'est 3 qui sort.
Tourj à l'entréej == 5 ?affichéj à la sortie
12non33
23non44
34non55
45oui—verif = 18 → sortie
⚠️ m = 18 ne sert à rien

La variable m est déclarée, initialisée… et jamais utilisée. Elle n'est là que pour brouiller la lecture — et la valeur 18 réapparaît dans verif=18 pour renforcer l'illusion d'un lien.

Dans un exercice de trace, listez d'abord les variables réellement utilisées. Celles qui restent sont du décor.

④Ternaire, dans le mauvais sens Facile

C
#include <stdio.h>
int main()
{ int a=15, b=23;
   printf("%d\n",(a>b)?b:a);
}
✅ Correction
sortie réelle
15

a > b s'écrit 15 > 23 : faux. On prend donc la branche de droite — a — qui vaut 15.

⚠️ Ce n'est pas le maximum

La forme habituelle est (a>b) ? a : b, qui donne le plus grand. Ici les deux branches sont inversées : ? b : a. Le programme renvoie le minimum.

Lire un ternaire, c'est lire trois choses dans l'ordre : la condition, puis ce qu'on fait si vrai, puis si faux. Ne jamais le reconnaître « de loin ».

⑤Deux incréments par tour Difficile

C
#include <stdio.h>
int main()
{ int n = 8, i ;
   for ( i = 3 ; i<n ; i+=3 )
     printf ("%d - " , i++);
}
✅ Correction
sortie réelle
3 - 7 - 

i est modifié deux fois par tour : le i++ du printf ajoute 1, puis le i += 3 de la boucle ajoute 3. Soit +4 à chaque passage.

Touri au testi<8 ?affichéaprès i++après i+=3
13oui3 - 47
27oui7 - 811
311nonla boucle s'arrête

i++ étant un post-incrément, c'est l'ancienne valeur qui est affichée : 3 puis 7, et non 4 puis 8.

💡 Ce que cet exercice enseigne vraiment

Modifier la variable de boucle à l'intérieur du corps rend le programme imprévisible à la lecture. Ici c'est volontaire, pour l'exercice. Dans votre code, ne le faites jamais : le for doit être le seul à toucher son compteur.

⑥Encore le point-virgule Moyen

C
#include <stdio.h>
int main()
{ int m=5, j;
    for(j=3; j<=m; ++j);
    printf("%d-",j);
}
✅ Correction
sortie réelle
6-

Même piège que le programme ①, avec une nuance : la condition est j <= m, c'est-à-dire j <= 5. La boucle s'arrête donc quand j vaut 6, et non 5.

++j ou j++ ne change rien ici : personne n'utilise la valeur renvoyée, seul l'effet compte.

🧰 La règle générale des deux programmes

Après une boucle for terminée normalement, le compteur vaut la première valeur qui rend la condition fausse :

  • i < 5 → i sort à 5
  • j <= 5 → j sort à 6

C'est aussi la raison pour laquelle un tableau de 5 cases se parcourt avec i < 5 : à la sortie, i vaut 5, soit exactement une case de trop — celle qui n'existe pas.

09TP 3 · Quatre fonctions simples

1La moyenne de deux mesures Facile

Écrire une fonction Moyenne qui reçoit deux nombres réels et retourne leur moyenne. Le programme principal doit demander deux mesures, appeler la fonction et afficher le résultat.

✅ Correction
C
#include <stdio.h>

float Moyenne(float a, float b)
{
    return (a + b) / 2;
}

int main(void)
{
    float m1, m2;

    printf("Saisir la première mesure : ");
    scanf("%f", &m1);
    printf("Saisir la deuxième mesure : ");
    scanf("%f", &m2);

    printf("\nLa moyenne est : %.2f\n", Moyenne(m1, m2));
    return 0;
}
sortie réelle — saisies : 18.5 puis 21.5
Saisir la première mesure : 18.5
Saisir la deuxième mesure : 21.5

La moyenne est : 20.00
⚠️ (a + b) / 2 et non a + b / 2

La division est prioritaire sur l'addition. Sans les parenthèses, le programme calcule a + (b / 2), soit 29,25 au lieu de 20. Il compile, il tourne, et il se trompe.

Ici les deux opérandes sont des float, donc la division est réelle. Avec des entiers, (a + b) / 2 tronquerait — c'est le piège de l'exercice 4.

2Un octet IPv4 est-il valide ? Facile

Écrire une fonction EstValide qui reçoit un entier représentant un octet d'adresse IPv4 et retourne 1 si la valeur est comprise entre 0 et 255, 0 sinon.

✅ Correction
C
#include <stdio.h>

int EstValide(int valeur)
{
    if (valeur >= 0 && valeur <= 255)
    {
        return 1;
    }
    return 0;
}

int main(void)
{
    int valeur;

    printf("Saisir une valeur : ");
    scanf("%d", &valeur);

    if (EstValide(valeur))
    {
        printf("La valeur est valide.\n");
    }
    else
    {
        printf("La valeur est invalide.\n");
    }
    return 0;
}
sortie réelle — saisies : 192
Saisir une valeur : 192
La valeur est valide.
sortie réelle — saisies : 300
Saisir une valeur : 300
La valeur est invalide.
💡 if (EstValide(valeur)) se suffit à lui-même

Écrire if (EstValide(valeur) == 1) fonctionne, mais c'est redondant : en C, toute valeur non nulle est vraie. Une fonction qui rend 1 ou 0 s'utilise directement comme condition.

C'est d'ailleurs pour cela que la consigne demande 1 et 0 plutôt que, disons, 1 et 2 : le résultat s'emboîte dans un if.

⚠️ 0 <= valeur <= 255 ne veut pas dire ce que vous croyez

Cette écriture, juste en mathématiques, est acceptée par le compilateur et toujours vraie. Le C évalue 0 <= valeur, ce qui donne 0 ou 1, puis compare ce résultat à 255 — toujours inférieur.

Il faut deux comparaisons reliées par &&. C'est une des rares fautes que le compilateur ne signale pas du tout.

3Le débit moyen d'un téléchargement Facile

Écrire une fonction CalculerDebit qui reçoit la taille d'un fichier en Mo et le temps de téléchargement en secondes, et retourne le débit moyen en Mo/s.

✅ Correction
C
#include <stdio.h>

float CalculerDebit(float taille, float temps)
{
    return taille / temps;
}

int main(void)
{
    float taille, temps;

    printf("Taille du fichier : ");
    scanf("%f", &taille);
    printf("Temps de téléchargement : ");
    scanf("%f", &temps);

    printf("\nDébit moyen : %.2f Mo/s\n", CalculerDebit(taille, temps));
    return 0;
}
sortie réelle — saisies : 120 puis 10
Taille du fichier : 120
Temps de téléchargement : 10

Débit moyen : 12.00 Mo/s
⚠️ Mo/s et Mb/s ne sont pas la même unité

L'énoncé demande des Mo/s — des méga-octets. Les débits des fournisseurs d'accès s'annoncent en Mb/s, des méga-bits. Un octet valant huit bits, 12 Mo/s font 96 Mb/s.

L'exercice 6 du même TP parle, lui, de Mb/s. Lire l'unité avant d'écrire la formule.

4Le taux de perte de paquets Moyen

Écrire une fonction CalculerTauxPerte qui reçoit le nombre de paquets envoyés et le nombre de paquets perdus, et retourne le taux de perte en pourcentage.

✅ Correction
C
#include <stdio.h>

float CalculerTauxPerte(int envoyes, int perdus)
{
    return (float) perdus / envoyes * 100;
}

int main(void)
{
    int envoyes, perdus;

    printf("Nombre de paquets envoyés : ");
    scanf("%d", &envoyes);
    printf("Nombre de paquets perdus : ");
    scanf("%d", &perdus);

    printf("\nTaux de perte : %.2f %%\n", CalculerTauxPerte(envoyes, perdus));
    return 0;
}
sortie réelle — saisies : 500 puis 25
Nombre de paquets envoyés : 500
Nombre de paquets perdus : 25

Taux de perte : 5.00 %
⚠️ Le piège de cet exercice : (float)

Les deux paramètres sont des int. En C, entier divisé par entier donne un entier : 25 / 500 vaut 0, pas 0,05. Le taux affiché serait alors 0.00 %.

La conversion (float) perdus force la division à se faire en réels.

C — les trois écritures
(float) perdus / envoyes * 100     /* juste : division réelle */
perdus * 100.0 / envoyes           /* juste aussi : 100.0 est un réel */
perdus / envoyes * 100             /* FAUX : donne 0 */

La deuxième forme marche parce que multiplier par 100.0 avant de diviser rend l'expression réelle. Les deux sont acceptables ; la troisième est l'erreur classique.

💡 Pourquoi %% dans le printf

Le caractère % introduit un format. Pour afficher un pourcentage littéral, il faut le doubler : %%. Écrire un seul % en fin de chaîne produit un affichage imprévisible.

10TP 3 · Trois tableaux à parcourir

5Sept températures Moyen

Un technicien relève la température d'un équipement réseau pendant 7 jours. Déclarer un tableau de 7 réels, demander les 7 températures, les afficher toutes, puis calculer et afficher la moyenne.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    float temperatures[7];
    float somme = 0.0f;
    int i;

    for (i = 0; i < 7; i++)
    {
        printf("Température %d : ", i + 1);
        scanf("%f", &temperatures[i]);
        somme = somme + temperatures[i];
    }

    printf("\nTempératures relevées :\n");
    for (i = 0; i < 7; i++)
    {
        printf("%.1f  ", temperatures[i]);
    }
    printf("\n\nTempérature moyenne : %.1f °C\n", somme / 7);
    return 0;
}
sortie réelle — saisies : 21.5, 22.0, 23.5, 22.5, 21.0, 23.0, 23.5
Température 1 : 21.5
Température 2 : 22.0
Température 3 : 23.5
Température 4 : 22.5
Température 5 : 21.0
Température 6 : 23.0
Température 7 : 23.5

Températures relevées :
21.5  22.0  23.5  22.5  21.0  23.0  23.5

Température moyenne : 22.4 °C
🧭 Additionner pendant la saisie, ou après ?

Ici la somme s'accumule dans la boucle de saisie : un seul parcours suffit. On aurait pu faire une deuxième boucle pour la somme — le résultat serait identique.

Le premier choix est plus court ; le second sépare mieux « saisir » de « calculer », ce qui devient utile dès que le programme grandit. C'est exactement le raisonnement qui mène aux exercices 8 et 9.

⚠️ somme doit être initialisée

Écrire float somme; sans = 0.0f laisse la variable avec une valeur indéterminée — ce qui traînait en mémoire à cet endroit. La moyenne sera fausse, parfois de peu, parfois de beaucoup, et différemment à chaque exécution.

6Huit débits : moyenne et maximum Moyen

Un administrateur mesure le débit d'une connexion à 8 moments. Déclarer un tableau de 8 réels, saisir les valeurs, les afficher, calculer le débit moyen et déterminer le débit maximum.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    float debits[8];
    float somme = 0.0f, max;
    int i;

    for (i = 0; i < 8; i++)
    {
        printf("Débit %d : ", i + 1);
        scanf("%f", &debits[i]);
        somme = somme + debits[i];
    }

    max = debits[0];
    for (i = 1; i < 8; i++)
    {
        if (debits[i] > max)
        {
            max = debits[i];
        }
    }

    printf("\nDébits mesurés :\n");
    for (i = 0; i < 8; i++)
    {
        printf("%.0f  ", debits[i]);
    }
    printf("\n\nDébit moyen : %.2f Mb/s\n", somme / 8);
    printf("Débit maximum : %.0f Mb/s\n", max);
    return 0;
}
sortie réelle — saisies : 95, 102, 98, 110, 105, 97, 115, 101
Débit 1 : 95
Débit 2 : 102
Débit 3 : 98
Débit 4 : 110
Débit 5 : 105
Débit 6 : 97
Débit 7 : 115
Débit 8 : 101

Débits mesurés :
95  102  98  110  105  97  115  101

Débit moyen : 102.88 Mb/s
Débit maximum : 115 Mb/s
⚠️ Le maximum part de debits[0], pas de zéro

Initialiser max = 0 semble naturel et marche ici, parce que tous les débits sont positifs. Mais sur des valeurs négatives — un écart, une variation — la fonction renverrait 0, une valeur absente du tableau.

Partir de la première valeur réelle et boucler à partir de i = 1 est juste dans tous les cas. C'est la forme à retenir.

7Chercher une valeur, et dire où Moyen

On considère les derniers octets de dix adresses IP. Déclarer un tableau de 10 entiers, saisir les valeurs, les afficher, demander une valeur à rechercher, indiquer si elle existe et afficher sa position.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    int octets[10];
    int i, cherche, position = -1;

    for (i = 0; i < 10; i++)
    {
        printf("Valeur %d : ", i + 1);
        scanf("%d", &octets[i]);
    }

    printf("\nValeurs :\n");
    for (i = 0; i < 10; i++)
    {
        printf("%d  ", octets[i]);
    }

    printf("\n\nValeur recherchée : ");
    scanf("%d", &cherche);

    for (i = 0; i < 10; i++)
    {
        if (octets[i] == cherche)
        {
            position = i;
            break;
        }
    }

    if (position >= 0)
    {
        printf("\nLa valeur %d a été trouvée à la position %d.\n", cherche, position);
    }
    else
    {
        printf("\nLa valeur %d ne figure pas dans le tableau.\n", cherche);
    }
    return 0;
}
sortie réelle — saisies : 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 30
Valeur 1 : 10
Valeur 2 : 15
Valeur 3 : 20
Valeur 4 : 25
Valeur 5 : 30
Valeur 6 : 35
Valeur 7 : 40
Valeur 8 : 45
Valeur 9 : 50
Valeur 10 : 55

Valeurs :
10  15  20  25  30  35  40  45  50  55

Valeur recherchée : 30

La valeur 30 a été trouvée à la position 4.
💡 Position 4, parce qu'on compte 0 1 2 3 4

La position d'une valeur dans un tableau, c'est son indice — et les indices commencent à 0.

calcul
valeur   10   15   20   25   30   35   40   45   50   55
indice    0    1    2    3    4    5    6    7    8    9
                                  ↑
                             position 4

C'est pourquoi la variable de la boucle, i, est déjà la réponse : on écrit position = i; et il n'y a rien à ajuster.

Le seul endroit où l'on décale, c'est quand on parle à l'utilisateur : printf("Valeur %d : ", i + 1) pour dire « première, deuxième… ». À l'intérieur du programme, l'indice reste l'indice.

🧭 Pourquoi position = -1 au départ

Il faut une valeur qui signifie « pas encore trouvé » et qui ne puisse pas être confondue avec un indice valide. Les indices vont de 0 à 9, donc -1 convient — 0 ne conviendrait pas, c'est un indice réel.

break arrête la boucle dès la première occurrence. Sans lui, on obtiendrait la dernière position en cas de doublon.

11TP 3 · Découper en fonctions

Les deux derniers exercices demandent le même travail que les précédents, mais réparti en fonctions. C'est là que se joue le chapitre.

8L'utilisation du processeur, en quatre fonctions Moyen

Un administrateur relève l'utilisation du processeur d'un serveur sur 10 mesures. Le programme doit utiliser SaisirTableau(), AfficherTableau(), CalculerMoyenne() et Maximum(), et le programme principal doit appeler ces fonctions.

✅ Correction
C
#include <stdio.h>

void  SaisirTableau(float t[], int n);
void  AfficherTableau(float t[], int n);
float CalculerMoyenne(float t[], int n);
float Maximum(float t[], int n);

int main(void)
{
    float cpu[10];

    SaisirTableau(cpu, 10);

    printf("\nUtilisation CPU :\n");
    AfficherTableau(cpu, 10);

    printf("\n\nUtilisation moyenne : %.2f %%\n", CalculerMoyenne(cpu, 10));
    printf("Utilisation maximale : %.0f %%\n", Maximum(cpu, 10));
    return 0;
}

void SaisirTableau(float t[], int n)
{
    int i;
    for (i = 0; i < n; i++)
    {
        printf("Mesure %d : ", i + 1);
        scanf("%f", &t[i]);
    }
}

void AfficherTableau(float t[], int n)
{
    int i;
    for (i = 0; i < n; i++)
    {
        printf("%.0f  ", t[i]);
    }
}

float CalculerMoyenne(float t[], int n)
{
    float somme = 0.0f;
    int i;
    for (i = 0; i < n; i++)
    {
        somme = somme + t[i];
    }
    return somme / n;
}

float Maximum(float t[], int n)
{
    float max = t[0];
    int i;
    for (i = 1; i < n; i++)
    {
        if (t[i] > max)
        {
            max = t[i];
        }
    }
    return max;
}
sortie réelle — saisies : 45, 52, 61, 70, 55, 48, 63, 72, 68, 50
Mesure 1 : 45
Mesure 2 : 52
…
Mesure 10 : 50

Utilisation CPU :
45  52  61  70  55  48  63  72  68  50

Utilisation moyenne : 58.40 %
Utilisation maximale : 72 %
🧰 Les deux choses à comprendre ici

1. SaisirTableau ne retourne rien, et pourtant elle remplit le tableau. Parce qu'elle en reçoit l'adresse : ce qu'elle écrit dans t[i] est écrit dans cpu[i]. Avec une variable simple, ce serait impossible.

2. Chaque fonction reçoit n. Un tableau passé en paramètre perd sa taille — sizeof(t) vaudrait 8, la taille d'une adresse, et non 40. Sans le second paramètre, aucune de ces boucles ne saurait où s'arrêter.

Les deux points sont démontrés dans le cours, section 8, sorties à l'appui.

💡 float t[] ou float *t : c'est pareil

Les deux écritures sont strictement équivalentes pour le compilateur. La première dit l'intention — « je reçois un tableau » — la seconde dit la réalité — « je reçois une adresse ».

Préférez float t[] en TP : elle se lit mieux, et le jour où vous verrez les pointeurs, vous saurez déjà que c'est la même chose.

9Les notes d'un groupe, en cinq fonctions Moyen

Un tableau de 10 notes sur 20. Écrire un programme utilisant SaisirNotes(), AfficherNotes(), CalculerMoyenne(), CompterAdmis() — le nombre de notes supérieures ou égales à 10 — et NoteMax().

✅ Correction
C
#include <stdio.h>

void  SaisirNotes(float t[], int n);
void  AfficherNotes(float t[], int n);
float CalculerMoyenne(float t[], int n);
int   CompterAdmis(float t[], int n);
float NoteMax(float t[], int n);

int main(void)
{
    float notes[10];

    SaisirNotes(notes, 10);

    printf("\nNotes :\n");
    AfficherNotes(notes, 10);

    printf("\n\nMoyenne : %.2f\n", CalculerMoyenne(notes, 10));
    printf("Nombre d'admis : %d\n", CompterAdmis(notes, 10));
    printf("Meilleure note : %.0f\n", NoteMax(notes, 10));
    return 0;
}

void SaisirNotes(float t[], int n)
{
    int i;
    for (i = 0; i < n; i++)
    {
        printf("Note %d : ", i + 1);
        scanf("%f", &t[i]);
    }
}

void AfficherNotes(float t[], int n)
{
    int i;
    for (i = 0; i < n; i++)
    {
        printf("%.0f  ", t[i]);
    }
}

float CalculerMoyenne(float t[], int n)
{
    float somme = 0.0f;
    int i;
    for (i = 0; i < n; i++)
    {
        somme = somme + t[i];
    }
    return somme / n;
}

int CompterAdmis(float t[], int n)
{
    int i, admis = 0;
    for (i = 0; i < n; i++)
    {
        if (t[i] >= 10)
        {
            admis = admis + 1;
        }
    }
    return admis;
}

float NoteMax(float t[], int n)
{
    float max = t[0];
    int i;
    for (i = 1; i < n; i++)
    {
        if (t[i] > max)
        {
            max = t[i];
        }
    }
    return max;
}
sortie réelle — saisies : 12, 8, 15, 11, 9, 14, 16, 10, 7, 13
Note 1 : 12
Note 2 : 8
…
Note 10 : 13

Notes :
12  8  15  11  9  14  16  10  7  13

Moyenne : 11.50
Nombre d'admis : 7
Meilleure note : 16
⚠️ >= et non > pour les admis

« Supérieures ou égales à 10 » : la note de 10 compte. Avec >, on obtiendrait 6 admis au lieu de 7 — et rien ne le signalerait.

Contrôle de cohérence à faire de tête : dans 12 8 15 11 9 14 16 10 7 13, les notes sous 10 sont 8, 9 et 7. Trois recalés, donc sept admis. ✔

🧭 CompterAdmis retourne un int

Les quatre autres fonctions rendent des float, parce qu'elles manipulent des notes. Celle-ci compte des personnes : le type de retour suit ce qu'on compte, pas ce qu'on parcourt.

C'est le genre de détail qui se voit sur une copie : un float pour un nombre d'étudiants ferait afficher « 7.00 admis ».

10Vérifier ses résultats sans tout ressaisir Facile

Retaper dix valeurs pour contrôler un chiffre est une perte de temps — et une source d'erreurs de plus. Ce petit programme reprend les mêmes fonctions avec les données de l'énoncé déjà écrites dans le code, et affiche tous les résultats attendus d'un coup.

Compilez-le une fois, gardez-le : il vous dira en une seconde si votre version interactive calcule juste.

✅ Le programme de contrôle
C — contrôle, sans saisie
#include <stdio.h>

float CalculerMoyenne(float t[], int n)
{
    float somme = 0.0f;
    int i;
    for (i = 0; i < n; i++)
    {
        somme = somme + t[i];
    }
    return somme / n;
}

float Maximum(float t[], int n)
{
    float max = t[0];
    int i;
    for (i = 1; i < n; i++)
    {
        if (t[i] > max)
        {
            max = t[i];
        }
    }
    return max;
}

int CompterAdmis(float t[], int n)
{
    int i, admis = 0;
    for (i = 0; i < n; i++)
    {
        if (t[i] >= 10)
        {
            admis = admis + 1;
        }
    }
    return admis;
}

int main(void)
{
    float temperatures[7] = {21.5, 22.0, 23.5, 22.5, 21.0, 23.0, 23.5};
    float cpu[10]   = {45, 52, 61, 70, 55, 48, 63, 72, 68, 50};
    float notes[10] = {12, 8, 15, 11, 9, 14, 16, 10, 7, 13};

    printf("ex.5  temperature moyenne : %.1f\n", CalculerMoyenne(temperatures, 7));
    printf("ex.8  utilisation moyenne : %.2f\n", CalculerMoyenne(cpu, 10));
    printf("ex.8  utilisation maximale : %.0f\n", Maximum(cpu, 10));
    printf("ex.9  moyenne : %.2f\n", CalculerMoyenne(notes, 10));
    printf("ex.9  admis : %d\n", CompterAdmis(notes, 10));
    printf("ex.9  meilleure note : %.0f\n", Maximum(notes, 10));
    return 0;
}
sortie
ex.5  temperature moyenne : 22.4
ex.8  utilisation moyenne : 58.40
ex.8  utilisation maximale : 72
ex.9  moyenne : 11.50
ex.9  admis : 7
ex.9  meilleure note : 16
💡 Pourquoi une version sans saisie au clavier

Les neuf corrections utilisent scanf. La vérification automatique de ce site les compile et les exécute, mais il ne peut pas comparer leur affichage : un programme qui lit au clavier mélange ses questions et vos réponses, et la transcription ne correspond plus à ce qu'il écrit vraiment.

Celui-ci ne lit rien. Sa sortie est donc recomparée caractère pour caractère à chaque contrôle — et avec elle les six chiffres du TP.

Une valeur juste une fois le reste : si un jour quelqu'un retouche CompterAdmis, la vérification le dira le jour même.

🧭 Maximum sert deux fois

La même fonction trouve le débit le plus élevé, l'utilisation CPU maximale et la meilleure note. Elle ne sait pas ce qu'elle compare — elle compare des float.

C'est tout l'intérêt du découpage : l'exercice 9 n'avait pas besoin d'une fonction NoteMax séparée, celle de l'exercice 8 suffisait. Le sujet en demande une, on la lui donne — mais son corps est identique.

12TP 3 · La méthode, en quatre gestes

Les neuf exercices suivent le même schéma. Une fois qu'on l'a vu, le TP se déroule tout seul.

Écrire une fonction, dans l'ordre
#GesteLa question à se poser
1Ce qu'elle reçoitde quoi a-t-elle besoin pour travailler ? → les paramètres
2Ce qu'elle rendune valeur, ou un affichage ? → le type de retour, ou void
3Le corpsle calcul, une seule tâche à la fois
4L'appeloù ranger le résultat ? → variable = fonction(…)
🧭 Le test qui dit si le découpage est bon

Une fonction doit pouvoir se décrire en une phrase sans « et ».

« Calcule la moyenne d'un tableau » — bonne fonction. « Saisit les notes et calcule la moyenne et affiche le résultat » — trois fonctions déguisées en une.

C'est précisément pour cela que l'exercice 9 en demande cinq : chacune fait une chose, et main ne fait qu'orchestrer.

⚠️ Les quatre fautes qui reviennent dans ce TP

La casse. Moyenne et moyenne sont deux fonctions différentes. Choisissez une convention et tenez-la.

La division entière. perdus / envoyes entre deux int donne 0. Il faut (float).

La borne de boucle. i < n, jamais i <= n.

La taille oubliée. Un tableau passé à une fonction a besoin de son n.

🤔 Pourquoi les prototypes sont-ils groupés en haut, aux exercices 8 et 9 ?

Pour que main vienne en premier. Le compilateur a besoin de connaître chaque fonction avant le premier appel ; les prototypes le lui disent, et les définitions peuvent alors venir après.

L'autre organisation — toutes les définitions avant main — marche aussi. Mais à cinq fonctions, il faut descendre au bas du fichier pour trouver le programme principal.

Sur une copie, grouper les prototypes montre qu'on a compris à quoi ils servent. C'est gratuit, et ça se voit.

13TP 4 · Les tableaux à deux dimensions

Trois énoncés, un seul geste : une boucle dans une boucle. Ce qui change d'un exercice à l'autre, c'est laquelle des deux on met à l'extérieur — et c'est tout le sujet. La syntaxe est au chapitre 21 du cours.

11La matrice des connexions entre serveurs Moyen

Quatre serveurs. Une matrice 4 × 4 où la ligne est le serveur qui établit la connexion, la colonne le serveur destinataire, et la case le nombre de connexions. Déclarer la matrice, la saisir, l'afficher en tableau, puis afficher le total général et le total par serveur émetteur.

✅ Correction
C
#include <stdio.h>

#define N 4

int main(void)
{
    int connexions[N][N];
    int i, j, total = 0;

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            printf("Connexions du serveur %d vers le serveur %d : ", i + 1, j + 1);
            scanf("%d", &connexions[i][j]);
        }
    }

    printf("\nMatrice des connexions :\n");
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%5d", connexions[i][j]);
        printf("\n");
    }

    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            total += connexions[i][j];
    printf("\nTotal des connexions : %d\n", total);

    printf("\nConnexions etablies par chaque serveur :\n");
    for (i = 0; i < N; i++) {
        int somme = 0;
        for (j = 0; j < N; j++)
            somme += connexions[i][j];
        printf("  serveur %d : %d\n", i + 1, somme);
    }
    return 0;
}
sortie réelle — saisies : 0, 12, 7, 3, 5, 0, 9, 2, 8, 4, 0, 11, 1, 6, 10, 0
Connexions du serveur 1 vers le serveur 1 : 0
Connexions du serveur 1 vers le serveur 2 : 12
Connexions du serveur 1 vers le serveur 3 : 7
Connexions du serveur 1 vers le serveur 4 : 3
Connexions du serveur 2 vers le serveur 1 : 5
...
Connexions du serveur 4 vers le serveur 4 : 0

Matrice des connexions :
    0   12    7    3
    5    0    9    2
    8    4    0   11
    1    6   10    0

Total des connexions : 78

Connexions etablies par chaque serveur :
  serveur 1 : 22
  serveur 2 : 16
  serveur 3 : 23
  serveur 4 : 17
🧭 « Par serveur » veut dire « par ligne »

L'énoncé dit « les connexions établies par chaque serveur ». Celui qui établit, c'est la ligne. On somme donc une ligne à la fois : i dehors, j dedans, et la remise à zéro de somme dans la boucle des i.

Si l'énoncé avait dit « connexions reçues par chaque serveur », il aurait fallu échanger les deux boucles. Même matrice, autre question, autre code.

⚠️ somme se remet à zéro à chaque ligne

Déclarée avant la boucle des lignes et jamais remise à zéro, elle cumulerait tout depuis le début : le serveur 2 afficherait 22 + 16 = 38, le serveur 3 afficherait 61, et le dernier donnerait le total général.

Le symptôme est reconnaissable : les valeurs montent toujours, et la dernière est juste. C'est une faute qui passe presque inaperçue sur des données bien choisies.

12Cinq jours de températures sur quatre serveurs Moyen

Une matrice 5 × 4 de float : une ligne par jour, une colonne par serveur. Saisir, afficher, puis donner la température moyenne de chaque serveur, le nombre de relevés au-dessus de 30 °C, et la température maximale enregistrée.

✅ Correction
C
#include <stdio.h>

#define JOURS    5
#define SERVEURS 4

int main(void)
{
    float temperatures[JOURS][SERVEURS];
    int i, j, chaudes = 0;
    float maximum;

    for (i = 0; i < JOURS; i++) {
        for (j = 0; j < SERVEURS; j++) {
            printf("Jour %d, serveur %d : ", i + 1, j + 1);
            scanf("%f", &temperatures[i][j]);
        }
    }

    printf("\nReleve des temperatures :\n");
    for (i = 0; i < JOURS; i++) {
        for (j = 0; j < SERVEURS; j++)
            printf("%8.1f", temperatures[i][j]);
        printf("\n");
    }

    printf("\nTemperature moyenne de chaque serveur :\n");
    for (j = 0; j < SERVEURS; j++) {
        float somme = 0;
        for (i = 0; i < JOURS; i++)
            somme += temperatures[i][j];
        printf("  serveur %d : %.2f C\n", j + 1, somme / JOURS);
    }

    maximum = temperatures[0][0];
    for (i = 0; i < JOURS; i++)
        for (j = 0; j < SERVEURS; j++) {
            if (temperatures[i][j] > 30.0)
                chaudes++;
            if (temperatures[i][j] > maximum)
                maximum = temperatures[i][j];
        }

    printf("\nReleves au-dessus de 30 C : %d\n", chaudes);
    printf("Temperature maximale : %.1f C\n", maximum);
    return 0;
}
sortie réelle — saisies : 22.5, 24.0, 31.2, 28.7, 23.1, 25.4, 33.8, 29.0, 21.9, 26.2, 30.5, 27.3, 24.8, 27.1, 34.6, 30.9, 22.0, 23.3, 29.8, 26.5
Jour 1, serveur 1 : 22.5
Jour 1, serveur 2 : 24.0
...
Jour 5, serveur 4 : 26.5

Releve des temperatures :
    22.5    24.0    31.2    28.7
    23.1    25.4    33.8    29.0
    21.9    26.2    30.5    27.3
    24.8    27.1    34.6    30.9
    22.0    23.3    29.8    26.5

Temperature moyenne de chaque serveur :
  serveur 1 : 22.86 C
  serveur 2 : 25.20 C
  serveur 3 : 31.98 C
  serveur 4 : 28.48 C

Releves au-dessus de 30 C : 5
Temperature maximale : 34.6 C
🧭 Ici, la boucle du dehors est celle des colonnes

« La moyenne de chaque serveur » — et le serveur est la colonne. On met donc j à l'extérieur et i à l'intérieur : on descend une colonne, on divise par 5, on passe à la suivante.

C'est le seul endroit du TP où les deux boucles sont inversées par rapport à l'habitude. Les écrire dans le mauvais ordre donne la moyenne du jour, pas celle du serveur — cinq valeurs au lieu de quatre, ce qui se voit.

⚠️ Le maximum part de la première case, pas de zéro

maximum = temperatures[0][0]; avant le parcours. Partir de 0 marche par chance ici — les températures sont positives — et serait faux dès qu'une mesure descend sous zéro, ce qui arrive dans un local technique mal chauffé.

Deux questions, un seul parcours : compter les relevés chauds et chercher le maximum tiennent dans la même double boucle.

💡 %.2f, %.1f : le format ne change pas la valeur

La moyenne du serveur 3 vaut 31.98 à deux décimales. Affichée en %.1f, elle donnerait 32.0 — arrondie à l'affichage, pas en mémoire. Le choix du format est une décision de lisibilité, jamais de calcul.

13Les tentatives de connexion, et une fonction qui reçoit la matrice Difficile

Un tableau 4 × 5 : une ligne par utilisateur, une colonne par jour, et le nombre de tentatives de connexion dans chaque case. Saisir, afficher, puis écrire une fonction totalUtilisateur() qui reçoit le tableau et un numéro de ligne et renvoie le total de cette ligne. L'appeler pour chaque utilisateur, et désigner celui qui a fait le plus de tentatives.

✅ Correction
C
#include <stdio.h>

#define UTILISATEURS 4
#define JOURS        5

int totalUtilisateur(int tentatives[][JOURS], int ligne);

int main(void)
{
    int tentatives[UTILISATEURS][JOURS];
    int i, j, total, meilleur = 0, record;

    for (i = 0; i < UTILISATEURS; i++) {
        for (j = 0; j < JOURS; j++) {
            printf("Utilisateur %d, jour %d : ", i + 1, j + 1);
            scanf("%d", &tentatives[i][j]);
        }
    }

    printf("\nTentatives de connexion :\n");
    for (i = 0; i < UTILISATEURS; i++) {
        for (j = 0; j < JOURS; j++)
            printf("%5d", tentatives[i][j]);
        printf("\n");
    }

    printf("\nTotal par utilisateur :\n");
    record = totalUtilisateur(tentatives, 0);
    for (i = 0; i < UTILISATEURS; i++) {
        total = totalUtilisateur(tentatives, i);
        printf("  utilisateur %d : %d tentative(s)\n", i + 1, total);
        if (total > record) {
            record = total;
            meilleur = i;
        }
    }

    printf("\nPlus grand nombre de tentatives : utilisateur %d (%d)\n",
           meilleur + 1, record);
    return 0;
}

int totalUtilisateur(int tentatives[][JOURS], int ligne)
{
    int j, somme = 0;
    for (j = 0; j < JOURS; j++)
        somme += tentatives[ligne][j];
    return somme;
}
sortie réelle — saisies : 3, 5, 2, 8, 1, 0, 1, 0, 2, 1, 12, 9, 15, 7, 11, 4, 4, 6, 3, 5
Utilisateur 1, jour 1 : 3
Utilisateur 1, jour 2 : 5
...
Utilisateur 4, jour 5 : 5

Tentatives de connexion :
    3    5    2    8    1
    0    1    0    2    1
   12    9   15    7   11
    4    4    6    3    5

Total par utilisateur :
  utilisateur 1 : 19 tentative(s)
  utilisateur 2 : 4 tentative(s)
  utilisateur 3 : 54 tentative(s)
  utilisateur 4 : 22 tentative(s)

Plus grand nombre de tentatives : utilisateur 3 (54)
⚠️ int t[][5] — la seconde taille est obligatoire

Le compilateur doit savoir la longueur d'une ligne pour trouver où commence la suivante : t[i][j] se trouve en mémoire à la position i × 5 + j. Sans ce 5, il ne peut rien calculer, et int t[][] est refusé — array has incomplete element type, un message qui ne dit pas franchement ce qui manque.

On peut écrire les deux tailles, int t[4][5] : c'est accepté, et la première est simplement ignorée.

🧭 Le champion se cherche pendant qu'on affiche

record est initialisé avec le total du premier utilisateur, pas avec 0. La boucle d'affichage sert aussi à comparer : un seul parcours, et meilleur retient l'indice, pas la valeur.

Retenir l'indice plutôt que la valeur est le réflexe à prendre : avec l'indice on peut tout retrouver — le nom, la ligne, les cinq jours de détail. Avec la seule valeur, on ne sait plus à qui elle appartient.

🤔 Et si deux utilisateurs étaient à égalité ?

Le test est total > record, strictement supérieur : en cas d'égalité, c'est le premier rencontré qui reste désigné.

Avec >=, ce serait le dernier. Aucune des deux réponses n'est fausse — mais l'énoncé ne dit pas laquelle il veut, et c'est le genre de détail qu'on signale en une ligne sur une copie.

⚠️ Les trois fautes de ce TP

L'accumulateur non remis à zéro entre deux lignes : les totaux montent toujours, et seul le dernier est juste.

Les boucles dans le mauvais ordre : on obtient la moyenne du jour au lieu de celle du serveur. Le compte des résultats le trahit — cinq au lieu de quatre.

La seconde taille oubliée dans le paramètre d'une fonction : le programme ne compile pas, et le message parle d'un type incomplet.

14TP 5 · Les pointeurs

Quatre énoncés, et une progression très nette : le premier parcourt un tableau dont on connaît la taille uniquement avec un pointeur ; les trois suivants n'ont plus de tableau du tout — la mémoire est réservée pendant l'exécution, selon un nombre que l'utilisateur donne. La syntaxe est aux chapitres 25 et 26 du cours.

🧭 Le même squelette dans les trois derniers
méthode
1.  scanf("%d", &n)                demander combien
2.  p = malloc(n * sizeof(int))    reserver
3.  if (p == NULL) return 1;       verifier
4.  ... p[i] ou *(p + i) ...       utiliser
5.  free(p);                       rendre

Seule l'étape 4 change d'un exercice à l'autre. Si l'on sait écrire les quatre autres de mémoire, le TP est fait.

12Huit mesures, parcourues au pointeur Facile

Un technicien relève huit mesures : {12, 18, 7, 25, 14, 9, 21, 16}. Déclarer le tableau, déclarer un pointeur p, l'initialiser avec l'adresse du premier élément, puis parcourir le tableau uniquement à l'aide du pointeur : afficher chaque mesure, calculer la somme, afficher la plus grande.

✅ Correction
C
#include <stdio.h>

int main(void)
{
    int mesures[8] = {12, 18, 7, 25, 14, 9, 21, 16};
    int *p = mesures;          /* 3. p recoit l'adresse du premier element */
    int somme = 0;
    int maxi;
    int i;

    maxi = *p;                 /* on part de la premiere mesure, pas de 0 */

    for (i = 0; i < 8; i++) {  /* 4. on ne parcourt QU'AVEC le pointeur */
        printf("mesure %d : %d\n", i + 1, *p);
        somme += *p;
        if (*p > maxi)
            maxi = *p;
        p++;
    }

    printf("somme            : %d\n", somme);
    printf("plus grande      : %d\n", maxi);
    return 0;
}
sortie réelle
mesure 1 : 12
mesure 2 : 18
mesure 3 : 7
mesure 4 : 25
mesure 5 : 14
mesure 6 : 9
mesure 7 : 21
mesure 8 : 16
somme            : 122
plus grande      : 25
⚠️ Partir de zéro pour chercher un maximum

maxi = 0; marche ici parce que toutes les mesures sont positives. Avec des températures négatives, le programme rendrait 0 — une valeur qui n'est pas dans le tableau. On part donc du premier élément : maxi = *p;.

🧭 « Uniquement à l'aide du pointeur »

L'énoncé interdit mesures[i]. On écrit *p et on avance par p++ — et surtout pas les deux écritures à la fois : p[i] avec p++ saute une case sur deux, c'est la faute démontrée au chapitre 25.

13Autant de valeurs que l'utilisateur veut Moyen

Le nombre de valeurs n'est pas connu à l'avance. Demander ce nombre, déclarer un pointeur, réserver la mémoire avec malloc(), saisir les valeurs, les afficher, calculer la somme et la moyenne, puis libérer avec free().

✅ Correction
C
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *p;
    int n, i, somme = 0;

    printf("Combien de valeurs ? ");
    scanf("%d", &n);

    p = malloc(n * sizeof(int));
    if (p == NULL) {
        printf("Allocation impossible\n");
        return 1;
    }

    for (i = 0; i < n; i++) {
        printf("valeur %d : ", i + 1);
        scanf("%d", &p[i]);
    }

    printf("\nValeurs saisies :\n");
    for (i = 0; i < n; i++) {
        printf("%d\n", p[i]);
        somme += p[i];
    }

    printf("somme   : %d\n", somme);
    printf("moyenne : %.2f\n", (float)somme / n);

    free(p);
    return 0;
}
sortie réelle — saisies : 4 puis 12, 18, 7, 25
Combien de valeurs ? valeur 1 : valeur 2 : valeur 3 : valeur 4 :
Valeurs saisies :
12
18
7
25
somme   : 62
moyenne : 15.50
⚠️ somme / n entre deux entiers donne un entier

Avec une somme de 62 et 4 valeurs, somme / n vaut 15, pas 15.5 : la division entière tronque. On écrit (float)somme / n pour forcer le calcul en réel — c'est la même règle que 6 / 7 au chapitre 7.

💡 L'invite et la saisie sur la même ligne

Combien de valeurs ? valeur 1 : valeur 2 : — les invites se suivent parce que ce que vous tapez n'apparaît pas dans la sortie enregistrée. À l'écran, chaque invite est bien suivie de ce que vous avez frappé.

14Chercher une valeur, et dire où elle est Moyen

Demander le nombre de valeurs, réserver la mémoire avec malloc(), la remplir, demander une valeur à rechercher, parcourir à l'aide du pointeur, dire si elle existe et, si oui, afficher sa position. Libérer.

✅ Correction
C
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *p;
    int n, i, cherchee, position = -1;

    printf("Combien de valeurs ? ");
    scanf("%d", &n);

    p = malloc(n * sizeof(int));
    if (p == NULL) {
        printf("Allocation impossible\n");
        return 1;
    }

    for (i = 0; i < n; i++) {
        printf("valeur %d : ", i + 1);
        scanf("%d", &p[i]);
    }

    printf("Valeur a rechercher : ");
    scanf("%d", &cherchee);

    for (i = 0; i < n; i++) {
        if (*(p + i) == cherchee) {
            position = i;
            break;
        }
    }

    if (position == -1)
        printf("%d ne figure pas dans la serie\n", cherchee);
    else
        printf("%d est a la position %d (le %d-eme)\n", cherchee, position, position + 1);

    free(p);
    return 0;
}
sortie réelle — saisies : 5 puis 12, 18, 7, 25, 14 puis 25
Combien de valeurs ? valeur 1 : valeur 2 : valeur 3 : valeur 4 : valeur 5 : Valeur a rechercher : 25 est a la position 3 (le 4-eme)
🧭 Position ou rang : on affiche les deux, et on le dit

La valeur 25 est à l'indice 3 et c'est la quatrième de la série. Les deux réponses sont justes, elles ne répondent pas à la même question. La convention du cours est celle de l'indice — « Position 4 car 0 1 2 3 4 » — et afficher les deux lève le doute sans rien trancher d'autorité.

⚠️ position = -1 au départ, et pas 0

0 est une position valable : c'est le premier élément. Pour dire « pas encore trouvé », il faut une valeur qu'un indice ne peut jamais prendre, et -1 est celle que tout le monde emploie.

Le break arrête à la première occurrence. Sans lui, on garderait la dernière.

15Un capteur, un nombre de mesures inconnu, et calloc Difficile

Un système industriel relève des mesures à intervalles réguliers ; le nombre est saisi au début. Allouer dynamiquement un tableau de float avec calloc, vérifier que l'allocation a réussi, saisir les mesures, les afficher en utilisant un pointeur, puis calculer la moyenne, la valeur minimale et la valeur maximale. Libérer.

✅ Correction
C
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    float *mesures;
    float somme = 0, mini, maxi;
    int n, i;

    printf("Combien de mesures ? ");
    scanf("%d", &n);

    mesures = calloc(n, sizeof(float));   /* calloc : n objets, chacun de sizeof(float) */
    if (mesures == NULL) {
        printf("Allocation impossible\n");
        return 1;
    }

    for (i = 0; i < n; i++) {
        printf("mesure %d : ", i + 1);
        scanf("%f", &mesures[i]);
    }

    mini = maxi = *mesures;               /* on part de la premiere mesure */

    printf("\nMesures enregistrees :\n");
    for (i = 0; i < n; i++) {
        printf("%.2f\n", *(mesures + i));
        somme += *(mesures + i);
        if (*(mesures + i) < mini) mini = *(mesures + i);
        if (*(mesures + i) > maxi) maxi = *(mesures + i);
    }

    printf("moyenne  : %.2f\n", somme / n);
    printf("minimale : %.2f\n", mini);
    printf("maximale : %.2f\n", maxi);

    free(mesures);
    return 0;
}
sortie réelle — saisies : 4 puis 18.5, 21.25, 17, 19.75
Combien de mesures ? mesure 1 : mesure 2 : mesure 3 : mesure 4 :
Mesures enregistrees :
18.50
21.25
17.00
19.75
moyenne  : 19.12
minimale : 17.00
maximale : 21.25
💡 C'est le seul énoncé du TP qui demande de vérifier l'allocation

Les trois premiers ne le demandent pas, et le cours ne le fait pas non plus dans ses premiers exemples. Le sujet va donc plus loin que la diapositive — comme le TP 3 allait plus loin que le chapitre sur les tableaux. Les trois lignes if (… == NULL) sont à mettre partout, pas seulement ici.

⚠️ %f pour lire un float, %lf pour un double

Avec scanf, le code de format doit correspondre exactement au type. scanf("%lf", &unFloat) écrit huit octets dans une case de quatre : le programme compile, tourne, et donne n'importe quoi.

À l'affichage, en revanche, printf("%f", …) accepte les deux : un float passé à printf est automatiquement promu en double.

💡 19,125 affiché « 19.12 »

La moyenne vaut exactement 19,125. %.2f arrondit au plus proche, et quand la valeur tombe pile entre deux, au pair — d'où 19.12 et non 19.13. Ce n'est pas une erreur de calcul, c'est la règle d'arrondi de printf.

16Le programme de contrôle, sans aucune saisie Facile

Les quatre corrections ci-dessus lisent au clavier : pour vérifier un résultat, il faut retaper huit mesures. Ce programme-ci porte les données de l'énoncé dans son code et affiche les quatre réponses d'un coup. Il sert à contrôler son propre travail — et c'est aussi le seul chemin par lequel la chaîne de relecture de ces fiches peut recomparer ces valeurs.

✅ Le programme et ses résultats
C
#include <stdio.h>
#include <stdlib.h>

/* Les quatre exercices du TP 5, SANS saisie : les donnees de l'enonce sont
   ecrites dans le programme. Il sert a verifier ses propres resultats sans
   retaper huit mesures a chaque essai — et c'est le seul chemin par lequel
   une valeur annoncee ici peut etre recomparee automatiquement. */

int main(void)
{
    /* --- exercice 1 : le tableau fixe de l'enonce -------------------- */
    int mesures[8] = {12, 18, 7, 25, 14, 9, 21, 16};
    int *p = mesures;
    int somme1 = 0, maxi = *p, i;

    for (i = 0; i < 8; i++) { somme1 += *p; if (*p > maxi) maxi = *p; p++; }
    printf("ex.1  somme = %d, maximum = %d\n", somme1, maxi);

    /* --- exercice 2 : quatre valeurs saisies, ici en dur ------------- */
    {
        int n = 4, j, somme = 0;
        int *q = malloc(n * sizeof(int));
        int jeu[4] = {12, 18, 7, 25};
        if (q == NULL) return 1;
        for (j = 0; j < n; j++) q[j] = jeu[j];
        for (j = 0; j < n; j++) somme += q[j];
        printf("ex.2  somme = %d, moyenne = %.2f\n", somme, (float)somme / n);
        free(q);
    }

    /* --- exercice 3 : recherche de 25 dans cinq valeurs -------------- */
    {
        int n = 5, j, cherchee = 25, position = -1;
        int *q = malloc(n * sizeof(int));
        int jeu[5] = {12, 18, 7, 25, 14};
        if (q == NULL) return 1;
        for (j = 0; j < n; j++) q[j] = jeu[j];
        for (j = 0; j < n; j++) if (*(q + j) == cherchee) { position = j; break; }
        printf("ex.3  %d trouve a la position %d\n", cherchee, position);
        free(q);
    }

    /* --- exercice 4 : quatre mesures reelles, calloc ----------------- */
    {
        int n = 4, j;
        float jeu[4] = {18.5f, 21.25f, 17.0f, 19.75f};
        float somme = 0, mini, maxi4;
        float *m = calloc(n, sizeof(float));
        if (m == NULL) return 1;
        for (j = 0; j < n; j++) m[j] = jeu[j];
        mini = maxi4 = *m;
        for (j = 0; j < n; j++) {
            somme += *(m + j);
            if (*(m + j) < mini)  mini  = *(m + j);
            if (*(m + j) > maxi4) maxi4 = *(m + j);
        }
        printf("ex.4  moyenne = %.2f, min = %.2f, max = %.2f\n",
               somme / n, mini, maxi4);
        free(m);
    }
    return 0;
}
sortie réelle
ex.1  somme = 122, maximum = 25
ex.2  somme = 62, moyenne = 15.50
ex.3  25 trouve a la position 3
ex.4  moyenne = 19.12, min = 17.00, max = 21.25

15TP 6 · Les structures

Sept énoncés, et une progression qui suit exactement celle du cours : une structure seule, puis un tableau de structures, puis des fonctions qui en reçoivent, puis un pointeur, puis l'allocation dynamique, et enfin une structure dans une structure. La syntaxe est aux chapitres 27 à 30 du cours.

🧭 Les trois questions à se poser avant d'écrire
méthode
1.  La fonction LIT-elle, ou ECRIT-elle ?
      lit   -> struct X v     (une copie suffit)     acces : v.champ
      ecrit -> struct X *v    (il faut l'adresse)    acces : v->champ

2.  Le nombre d'elements est-il connu A L'AVANCE ?
      oui -> struct X t[5];
      non -> struct X *t = malloc(n * sizeof(struct X));  ... free(t);

3.  Le champ est-il une CHAINE ?
      oui -> strcpy(v.nom, "...")  et  scanf("%s", v.nom)     sans &
      non -> v.age = 20            et  scanf("%d", &v.age)    avec &

Les sept exercices ne demandent rien d'autre que de répondre juste à ces trois questions. Celui qui les a en tête n'a plus qu'à taper.

17Un produit, et la valeur de son stock Facile

Définir une structure Produit avec le nom, le prix et la quantité en stock. Déclarer une variable de ce type, demander les informations à l'utilisateur, les afficher, puis calculer et afficher valeur = prix × quantité.

✅ Correction
C
#include <stdio.h>

struct Produit {
    char  nom[30];
    float prix;
    int   quantite;
};

int main(void)
{
    struct Produit p;

    printf("Nom du produit : ");
    scanf("%29s", p.nom);              /* 29 : on garde la place du \0 */
    printf("Prix unitaire  : ");
    scanf("%f", &p.prix);
    printf("Quantite       : ");
    scanf("%d", &p.quantite);

    printf("\n--- Fiche produit ---\n");
    printf("Nom      : %s\n", p.nom);
    printf("Prix     : %.2f EUR\n", p.prix);
    printf("Stock    : %d\n", p.quantite);
    printf("Valeur   : %.2f EUR\n", p.prix * p.quantite);
    return 0;
}
sortie réelle — saisies : cable-rj45, 3.90, 120
Nom du produit : Prix unitaire  : Quantite       :
--- Fiche produit ---
Nom      : cable-rj45
Prix     : 3.90 EUR
Stock    : 120
Valeur   : 468.00 EUR
⚠️ scanf("%s", …) sans largeur est un trou de sécurité

Le champ fait 30 caractères ; %s seul en écrira autant qu'on en tape, par-dessus ce qui suit en mémoire. On écrit donc %29s — vingt-neuf, pas trente : il faut garder la place du \0 qui termine toute chaîne en C.

Et pas de & devant p.nom : c'est un tableau, donc déjà une adresse. &p.prix, lui, en a besoin.

💡 prix × quantité mélange un réel et un entier

float × int donne un float : le C promeut l'entier automatiquement. C'est l'un des rares endroits où le mélange de types ne piège personne — contrairement à int / int, qui tronque.

18Un véhicule, et son kilométrage mis à jour Facile

Définir une structure Vehicule (marque, modèle, année, kilométrage). L'initialiser avec des valeurs au choix, afficher ses informations, demander un nouveau kilométrage, le mettre à jour, puis réafficher.

✅ Correction
C
#include <stdio.h>
#include <string.h>

struct Vehicule {
    char marque[30];
    char modele[30];
    int  annee;
    int  kilometrage;
};

void afficher(struct Vehicule v)
{
    printf("%s %s (%d) — %d km\n", v.marque, v.modele, v.annee, v.kilometrage);
}

int main(void)
{
    struct Vehicule v = { "Renault", "Kangoo", 2019, 86500 };
    int nouveau;

    printf("Avant  : ");  afficher(v);

    printf("Nouveau kilometrage : ");
    scanf("%d", &nouveau);
    v.kilometrage = nouveau;

    printf("Apres  : ");  afficher(v);
    return 0;
}
sortie réelle — saisies : 91200
Avant  : Renault Kangoo (2019) — 86500 km
Nouveau kilometrage : Apres  : Renault Kangoo (2019) — 91200 km
💡 L'initialisation à la déclaration évite quatre lignes

struct Vehicule v = { "Renault", "Kangoo", 2019, 86500 }; remplit les quatre champs dans l'ordre de la définition. C'est le seul endroit où une chaîne se pose avec = : partout ailleurs, il faut strcpy.

Plus sûr encore : { .marque = "Renault", .annee = 2019 }. Le jour où un champ est ajouté au milieu de la structure, la première écriture décale tout en silence — la seconde non.

🧭 afficher prend une copie, et c'est voulu

Elle ne fait que lire. Une copie de quatre champs ne coûte rien, et le prototype void afficher(struct Vehicule v) dit à qui le lit que la fonction ne touchera à rien. C'est une information, pas une économie.

19Cinq produits, et la valeur totale du stock Moyen

Déclarer un tableau de 5 Produit, saisir les informations des cinq, les afficher, puis calculer et afficher la valeur totale du stock.

✅ Correction
C
#include <stdio.h>

#define N 5

struct Produit {
    char  nom[30];
    float prix;
    int   quantite;
};

int main(void)
{
    struct Produit stock[N];
    float total = 0;
    int i;

    for (i = 0; i < N; i++) {
        printf("Produit %d — nom      : ", i + 1);
        scanf("%29s", stock[i].nom);
        printf("Produit %d — prix     : ", i + 1);
        scanf("%f", &stock[i].prix);
        printf("Produit %d — quantite : ", i + 1);
        scanf("%d", &stock[i].quantite);
    }

    printf("\n%-14s %10s %6s %12s\n", "PRODUIT", "PRIX", "QTE", "VALEUR");
    for (i = 0; i < N; i++) {
        float valeur = stock[i].prix * stock[i].quantite;
        printf("%-14s %10.2f %6d %12.2f\n",
               stock[i].nom, stock[i].prix, stock[i].quantite, valeur);
        total += valeur;
    }
    printf("%-14s %29.2f\n", "TOTAL", total);
    return 0;
}
sortie réelle — saisies : les cinq produits ci-dessous
PRODUIT              PRIX    QTE       VALEUR
cable-rj45           3.90    120       468.00
switch-8p           89.00      4       356.00
onduleur           149.50      2       299.00
disque-1to          62.25      7       435.75
clavier             18.80     15       282.00
TOTAL                                1840.75
🧭 tableau[i].champ — on lit de gauche à droite

stock[i] est un produit, et .prix est son champ. Les deux notations se combinent sans règle nouvelle : il n'y a pas de « syntaxe des tableaux de structures », il y a un tableau, et des structures.

&stock[i].quantite se lit de la même façon : on prend l'adresse du champ, pas celle du tableau.

🔧 Trois formats qui font un tableau lisible

%-14s — chaîne sur 14 colonnes, collée à gauche (le tiret) · %10.2f — réel sur 10 colonnes, 2 décimales · %6d — entier sur 6 colonnes, collé à droite.

Aucun espace n'est écrit à la main. Un alignement fait d'espaces tapés se défait au premier nombre plus long.

⚠️ #define N 5 plutôt que 5 partout

Le 5 apparaît dans la déclaration et dans deux boucles. Écrit trois fois, il sera changé deux fois le jour où le stock passe à huit — et la troisième occurrence fera lire une case qui n'existe pas, sans aucun message.

20Deux fonctions : saisir, afficher Moyen

Avec la structure Ordinateur (modèle, RAM en Go, stockage en Go, prix), créer void saisirOrdinateur(…) et void afficherOrdinateur(…). Dans main() : déclarer un ordinateur, appeler la saisie, puis l'affichage.

✅ Correction
C
#include <stdio.h>

struct Ordinateur {
    char  modele[30];
    int   ram;
    int   stockage;
    float prix;
};

/* Elle doit ÉCRIRE dans la structure de l'appelant : elle reçoit son adresse. */
void saisirOrdinateur(struct Ordinateur *o)
{
    printf("Modele        : ");  scanf("%29s", o->modele);
    printf("RAM (Go)      : ");  scanf("%d", &o->ram);
    printf("Stockage (Go) : ");  scanf("%d", &o->stockage);
    printf("Prix (EUR)    : ");  scanf("%f", &o->prix);
}

/* Elle ne fait que LIRE : une copie suffit. */
void afficherOrdinateur(struct Ordinateur o)
{
    printf("\n%s — %d Go de RAM, %d Go de stockage, %.2f EUR\n",
           o.modele, o.ram, o.stockage, o.prix);
}

int main(void)
{
    struct Ordinateur poste;
    saisirOrdinateur(&poste);
    afficherOrdinateur(poste);
    return 0;
}
sortie réelle — saisies : ThinkPad-T14, 16, 512, 980
Modele        : RAM (Go)      : Stockage (Go) : Prix (EUR)    :
ThinkPad-T14 — 16 Go de RAM, 512 Go de stockage, 980.00 EUR
🧭 Les points de suspension de l'énoncé cachent toute la question

Le sujet écrit void saisirOrdinateur(...); sans dire ce qu'il y a dans les parenthèses, et c'est la question de l'exercice.

FonctionElle…ParamètreAppelAccès
saisirOrdinateurécrit struct Ordinateur *osaisir(&poste) o->ram
afficherOrdinateurlit struct Ordinateur oafficher(poste) o.ram

Avec struct Ordinateur o en paramètre de la saisie, le programme compile, tourne, ne dit rien — et main affiche une structure vide. C'est la faute la plus coûteuse du TP, parce qu'elle est muette.

⚠️ scanf("%d", &o->ram) — les deux à la fois

o->ram désigne le champ ; & en prend l'adresse, dont scanf a besoin. Les deux ne font pas double emploi : la flèche traverse le pointeur, l'esperluette prend l'adresse de ce qu'on a trouvé au bout.

21Un capteur, modifié par un pointeur Moyen

Avec la structure Capteur (nom, valeur, seuil) : déclarer une variable, déclarer un pointeur vers elle, l'y faire pointer, puis tout faire par le pointeur — affecter les informations, modifier la valeur, modifier le seuil, afficher.

✅ Correction
C
#include <stdio.h>
#include <string.h>

struct Capteur {
    char  nom[30];
    float valeur;
    float seuil;
};

int main(void)
{
    struct Capteur c;
    struct Capteur *p;

    p = &c;                        /* p pointe vers c */

    strcpy(p->nom, "temperature-salle-serveurs");
    p->valeur = 21.5f;
    p->seuil  = 27.0f;
    printf("Depart  : %s = %.2f (seuil %.2f)\n", p->nom, p->valeur, p->seuil);

    p->valeur = 29.4f;             /* on modifie PAR LE POINTEUR */
    p->seuil  = 28.0f;
    printf("Modifie : %s = %.2f (seuil %.2f)\n", p->nom, p->valeur, p->seuil);

    if (p->valeur > p->seuil)
        printf("ALERTE : le seuil est depasse de %.2f\n", p->valeur - p->seuil);
    else
        printf("Rien a signaler.\n");

    printf("c.valeur vaut %.2f — c'est bien la MEME variable\n", c.valeur);
    return 0;
}
sortie réelle
Depart  : temperature-salle-serveurs = 21.50 (seuil 27.00)
Modifie : temperature-salle-serveurs = 29.40 (seuil 28.00)
ALERTE : le seuil est depasse de 1.40
c.valeur vaut 29.40 — c'est bien la MEME variable
🧭 La dernière ligne est la démonstration

Tout a été écrit par p, et c'est c qui a changé. Le pointeur n'a jamais contenu de capteur : il contenait l'adresse du capteur, et p->valeur allait écrire au bout.

C'est exactement ce que fait scanf depuis le premier jour, et ce que fera toute fonction qui modifie une structure.

💡 p->valeur ou (*p).valeur ?

Les deux sont rigoureusement identiques. Les parenthèses de la seconde ne sont pas facultatives — *p.valeur voudrait dire « le contenu du champ valeur de p », ce qui n'a pas de sens ici. La flèche existe précisément pour qu'on ne les oublie pas.

22Une bibliothèque de taille inconnue Difficile

Avec la structure Livre (titre, auteur, année, prix) : demander le nombre de livres, allouer dynamiquement un tableau de structures, vérifier que l'allocation a réussi, saisir, afficher, puis trouver le livre le plus récent, calculer le prix moyen, et libérer la mémoire.

✅ Correction
C
#include <stdio.h>
#include <stdlib.h>

struct Livre {
    char  titre[50];
    char  auteur[30];
    int   annee;
    float prix;
};

int main(void)
{
    struct Livre *biblio;
    int n, i, recent = 0;
    float somme = 0;

    printf("Combien de livres ? ");
    scanf("%d", &n);
    if (n <= 0) { printf("Il en faut au moins un.\n"); return 1; }

    biblio = malloc(n * sizeof(struct Livre));
    if (biblio == NULL) {
        printf("Memoire insuffisante\n");
        return 1;
    }

    for (i = 0; i < n; i++) {
        printf("Livre %d — titre  : ", i + 1);  scanf("%49s", biblio[i].titre);
        printf("Livre %d — auteur : ", i + 1);  scanf("%29s", biblio[i].auteur);
        printf("Livre %d — annee  : ", i + 1);  scanf("%d", &biblio[i].annee);
        printf("Livre %d — prix   : ", i + 1);  scanf("%f", &biblio[i].prix);
    }

    printf("\n--- La bibliotheque ---\n");
    for (i = 0; i < n; i++) {
        printf("%-22s %-14s %4d  %7.2f EUR\n",
               biblio[i].titre, biblio[i].auteur, biblio[i].annee, biblio[i].prix);
        somme += biblio[i].prix;
        if (biblio[i].annee > biblio[recent].annee) recent = i;
    }

    printf("\nLe plus recent : %s (%s, %d)\n",
           biblio[recent].titre, biblio[recent].auteur, biblio[recent].annee);
    printf("Prix moyen     : %.2f EUR\n", somme / n);

    free(biblio);
    return 0;
}
sortie réelle — saisies : 3 livres
--- La bibliotheque ---
Le-C-en-pratique       Delannoy       2016    29.50 EUR
Reseaux                Tanenbaum      2011    54.00 EUR
Docker-en-action       Nickoloff      2019    42.00 EUR

Le plus recent : Docker-en-action (Nickoloff, 2019)
Prix moyen     : 41.83 EUR
🧭 Chercher un maximum : on retient l'INDICE, pas la valeur
C
int recent = 0;                                  /* le premier, par defaut */
for (i = 0; i < n; i++)
    if (biblio[i].annee > biblio[recent].annee)
        recent = i;                              /* on retient OU il est  */

Retenir l'année la plus grande ne servirait à rien : c'est le livre qu'on doit afficher, avec son titre et son auteur. L'indice les ramène tous les trois.

Et on part de 0, jamais d'une année inventée : recent = 0 dit « pour l'instant, le plus récent est le premier », ce qui est vrai avant d'avoir regardé les autres.

⚠️ sizeof(struct Livre), pas la somme des champs

50 + 30 + 4 + 4 = 88, et pourtant la structure en occupe souvent 92 : le compilateur ajoute des octets de remplissage pour aligner les champs. Une taille calculée à la main réserve trop peu, et l'écriture du dernier livre déborde.

💡 n <= 0 se teste AVANT malloc

malloc(0) est autorisé et rend un pointeur qu'on n'a pas le droit d'utiliser ; un n négatif donne une taille énorme une fois convertie. Le test coûte une ligne et évite les deux.

23Un équipement, et sa date d'achat Moyen

Définir struct Date (jour, mois, année), puis struct Equipement (nom, prix, et un champ dateAchat de type struct Date). Saisir le nom, le prix et les trois nombres de la date, puis tout afficher, la date sous la forme Date d'achat : 15/09/2026.

✅ Correction
C
#include <stdio.h>

struct Date {
    int jour;
    int mois;
    int annee;
};

struct Equipement {
    char        nom[30];
    float       prix;
    struct Date dateAchat;
};

int main(void)
{
    struct Equipement e;

    printf("Nom de l'equipement : ");  scanf("%29s", e.nom);
    printf("Prix (€)             : ");  scanf("%f", &e.prix);
    printf("Jour d'achat        : ");  scanf("%d", &e.dateAchat.jour);
    printf("Mois d'achat        : ");  scanf("%d", &e.dateAchat.mois);
    printf("Annee d'achat       : ");  scanf("%d", &e.dateAchat.annee);

    printf("\nNom : %s\n", e.nom);
    printf("Prix : %.2f €\n", e.prix);
    printf("Date d'achat : %02d/%02d/%d\n",
           e.dateAchat.jour, e.dateAchat.mois, e.dateAchat.annee);
    return 0;
}
sortie réelle — saisies : Ordinateur, 1250, 15, 9, 2026
Nom : Ordinateur
Prix : 1250.00 €
Date d'achat : 15/09/2026

C'est mot pour mot l'exemple d'affichage de l'énoncé — obtenu en exécutant le programme, pas recopié.

🧭 Un point par étage

e.dateAchat.jour se lit de gauche à droite : e → dateAchat → jour. Et scanf veut l'adresse du nombre, donc &e.dateAchat.jour — l'esperluette se met devant toute l'expression, pas au milieu.

⚠️ struct Date doit être définie AVANT

Le compilateur lit le fichier de haut en bas. Pour réserver la place d'un champ struct Date dateAchat, il doit déjà connaître la taille de struct Date — donc l'avoir lue. Inverser les deux définitions donne field has incomplete type.

💡 %02d : c'est ce qui donne « 09 » et non « 9 »

Le 0 dit « complète avec des zéros », le 2 dit « sur deux chiffres ». Sans lui, le 15 septembre s'écrit 15/9/2026 — et l'énoncé demande 15/09/2026.

24Le programme de contrôle, sans aucune saisie Facile

Les sept corrections lisent au clavier : pour vérifier un résultat, il faut retaper une bibliothèque entière. Celui-ci porte les données dans son code et affiche les sept réponses d'un coup. Il sert à contrôler son travail — et c'est le seul chemin par lequel la chaîne de relecture de ces fiches peut recomparer ces valeurs.

✅ Le programme et ses résultats
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Les sept exercices du TP 6, SANS aucune saisie : les donnees sont dans le
   programme. Il sert a verifier ses propres resultats sans retaper une
   bibliotheque entiere — et c'est le seul chemin par lequel une valeur
   annoncee ici peut etre recomparee automatiquement. */

struct Produit    { char nom[30]; float prix; int quantite; };
struct Vehicule   { char marque[30]; char modele[30]; int annee; int kilometrage; };
struct Ordinateur { char modele[30]; int ram; int stockage; float prix; };
struct Capteur    { char nom[30]; float valeur; float seuil; };
struct Livre      { char titre[50]; char auteur[30]; int annee; float prix; };
struct Date       { int jour; int mois; int annee; };
struct Equipement { char nom[30]; float prix; struct Date dateAchat; };

int main(void)
{
    /* ex.1 — un produit */
    struct Produit p = { "cable-rj45", 3.90f, 120 };
    printf("ex.1  valeur du stock = %.2f EUR\n", p.prix * p.quantite);

    /* ex.2 — un vehicule, kilometrage mis a jour */
    struct Vehicule v = { "Renault", "Kangoo", 2019, 86500 };
    v.kilometrage = 91200;
    printf("ex.2  %s %s (%d) = %d km\n", v.marque, v.modele, v.annee, v.kilometrage);

    /* ex.3 — cinq produits */
    struct Produit stock[5] = {
        { "cable-rj45",   3.90f, 120 }, { "switch-8p",   89.00f,  4 },
        { "onduleur",    149.50f,   2 }, { "disque-1to",  62.25f,  7 },
        { "clavier",      18.80f,  15 },
    };
    float total = 0;
    for (int i = 0; i < 5; i++) total += stock[i].prix * stock[i].quantite;
    printf("ex.3  valeur totale = %.2f EUR\n", total);

    /* ex.4 — un ordinateur, rempli par une fonction (ici en dur) */
    struct Ordinateur o = { "ThinkPad-T14", 16, 512, 980.00f };
    printf("ex.4  %s — %d Go RAM, %d Go, %.2f EUR\n", o.modele, o.ram, o.stockage, o.prix);

    /* ex.5 — un capteur, modifie PAR LE POINTEUR */
    struct Capteur c = { "temperature", 21.5f, 27.0f };
    struct Capteur *pc = &c;
    pc->valeur = 29.4f;
    pc->seuil  = 28.0f;
    printf("ex.5  %s = %.2f, seuil %.2f, depassement %.2f\n",
           pc->nom, c.valeur, c.seuil, c.valeur - c.seuil);

    /* ex.6 — une bibliotheque allouee dynamiquement */
    struct Livre jeu[4] = {
        { "Le-C-en-pratique", "Delannoy", 2016, 29.50f },
        { "Reseaux",          "Tanenbaum", 2011, 54.00f },
        { "Algorithmique",    "Cormen",    2010, 79.90f },
        { "Docker-en-action", "Nickoloff", 2019, 42.00f },
    };
    int n = 4, recent = 0;
    float somme = 0;
    struct Livre *biblio = malloc(n * sizeof(struct Livre));
    if (biblio == NULL) return 1;
    for (int i = 0; i < n; i++) biblio[i] = jeu[i];
    for (int i = 0; i < n; i++) {
        somme += biblio[i].prix;
        if (biblio[i].annee > biblio[recent].annee) recent = i;
    }
    printf("ex.6  le plus recent = %s (%d), prix moyen = %.2f EUR\n",
           biblio[recent].titre, biblio[recent].annee, somme / n);
    free(biblio);

    /* ex.7 — une structure dans une structure */
    struct Equipement e;
    strcpy(e.nom, "Ordinateur");
    e.prix = 1250.00f;
    e.dateAchat.jour = 15; e.dateAchat.mois = 9; e.dateAchat.annee = 2026;
    printf("ex.7  %s, %.2f EUR, achete le %02d/%02d/%d\n",
           e.nom, e.prix, e.dateAchat.jour, e.dateAchat.mois, e.dateAchat.annee);
    return 0;
}
sortie réelle
ex.1  valeur du stock = 468.00 EUR
ex.2  Renault Kangoo (2019) = 91200 km
ex.3  valeur totale = 1840.75 EUR
ex.4  ThinkPad-T14 — 16 Go RAM, 512 Go, 980.00 EUR
ex.5  temperature = 29.40, seuil 28.00, depassement 1.40
ex.6  le plus recent = Docker-en-action (2019), prix moyen = 51.35 EUR
ex.7  Ordinateur, 1250.00 EUR, achete le 15/09/2026

Le prix moyen diffère de celui de l'exercice 6 — 51,35 contre 41,83 — et ce n'est pas une erreur : le contrôle porte sur quatre livres, la saisie d'exemple n'en avait que trois. Deux jeux de données, deux moyennes ; c'est exactement pour ça qu'on les écrit dans le code.

16TP 7 · Les chaînes de caractères

Quatre exercices, et le même réflexe à chaque fois : une chaîne est un tableau, donc on la parcourt — et on réserve toujours une case de plus pour le '\0'.

25Analyser un mot saisi Facile

Exercice 1. Déclarer un tableau pouvant contenir un mot de 49 caractères maximum, le demander à l'utilisateur, afficher sa longueur avec strlen(), son premier et son dernier caractère, puis compter les voyelles (a, e, i, o, u, y) en minuscules et en majuscules.

✅ Correction
C
#include <stdio.h>
#include <string.h>

int main(void)
{
    char mot[50];
    size_t longueur;
    size_t i;
    int voyelles = 0;

    printf("Entrez un mot : ");
    scanf("%49s", mot);

    longueur = strlen(mot);
    printf("Longueur : %zu\n", longueur);
    printf("Premier caractere : %c\n", mot[0]);
    printf("Dernier caractere : %c\n", mot[longueur - 1]);

    for (i = 0; i < longueur; i++) {
        char c = mot[i];
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y'
         || c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || c == 'Y') {
            voyelles++;
        }
    }

    printf("Nombre de voyelles : %d\n", voyelles);

    return 0;
}
sortie réelle — saisies : Bonjour
Entrez un mot : Longueur : 7
Premier caractere : B
Dernier caractere : r
Nombre de voyelles : 3
⚠️ 49 caractères se déclarent [50]

Le sujet dit « 49 caractères maximum ». Le tableau en compte 50 : les 49 lettres, plus la case du '\0'. Et scanf("%49s", …) borne la saisie à ces 49 — sans cette borne, un mot plus long écrirait au-delà du tableau.

Le dernier caractère est à l'indice longueur − 1, jamais longueur : à cet indice-là se trouve le '\0'.

26Comparer et copier deux noms Facile

Exercice 2. Saisir deux noms, afficher la longueur de chacun, les comparer avec strcmp(), dire s'ils sont identiques, puis copier le premier dans un troisième tableau avec strcpy() et l'afficher.

✅ Correction
C
#include <stdio.h>
#include <string.h>

int main(void)
{
    char nom1[50];
    char nom2[50];
    char copie[50];

    printf("Premier nom  : ");
    scanf("%49s", nom1);
    printf("Deuxieme nom : ");
    scanf("%49s", nom2);

    printf("\nLongueur de %s : %zu\n", nom1, strlen(nom1));
    printf("Longueur de %s : %zu\n", nom2, strlen(nom2));

    if (strcmp(nom1, nom2) == 0) {
        printf("Les deux noms sont identiques.\n");
    } else {
        printf("Les deux noms ne sont pas identiques.\n");
    }

    strcpy(copie, nom1);
    printf("Copie du premier nom : %s\n", copie);

    return 0;
}
sortie réelle — saisies : Dupont puis Durand
Premier nom  : Deuxieme nom :
Longueur de Dupont : 6
Longueur de Durand : 6
Les deux noms ne sont pas identiques.
Copie du premier nom : Dupont

Deux noms de même longueur ne sont pas deux noms identiques : c'est strcmp qui tranche, pas strlen. L'exemple est choisi pour ça.

27Cinq serveurs, le plus long nom, et une recherche Moyen

Exercice 3. À partir du tableau char serveurs[5][30] donné dans l'énoncé : afficher chaque nom et sa longueur, déterminer le nom le plus long, puis demander un nom à rechercher et dire s'il existe.

✅ Correction
C
#include <stdio.h>
#include <string.h>

int main(void)
{
    char serveurs[5][30] = {
        "SRV_WEB",
        "SRV_DNS",
        "SRV_BDD",
        "SRV_FICHIERS",
        "SRV_BACKUP"
    };
    char recherche[30];
    int i;
    int plus_long = 0;
    int trouve = 0;

    printf("Liste des serveurs :\n");
    for (i = 0; i < 5; i++) {
        printf("  %s (%zu caracteres)\n", serveurs[i], strlen(serveurs[i]));
        if (strlen(serveurs[i]) > strlen(serveurs[plus_long])) {
            plus_long = i;
        }
    }

    printf("\nNom le plus long : %s\n", serveurs[plus_long]);

    printf("\nServeur a rechercher : ");
    scanf("%29s", recherche);

    for (i = 0; i < 5; i++) {
        if (strcmp(serveurs[i], recherche) == 0) {
            trouve = 1;
        }
    }

    if (trouve) {
        printf("Le serveur %s existe.\n", recherche);
    } else {
        printf("Le serveur %s est introuvable.\n", recherche);
    }

    return 0;
}
sortie réelle — saisies : SRV_DNS
Liste des serveurs :
  SRV_WEB (7 caracteres)
  SRV_DNS (7 caracteres)
  SRV_BDD (7 caracteres)
  SRV_FICHIERS (12 caracteres)
  SRV_BACKUP (10 caracteres)

Nom le plus long : SRV_FICHIERS

Serveur a rechercher : Le serveur SRV_DNS existe.
💡 char serveurs[5][30] : cinq casiers de trente

C'est un tableau à deux dimensions, exactement comme les matrices du TP 4 — sauf que chaque ligne est une chaîne. serveurs[i] désigne la chaîne numéro i, et serveurs[i][j] son j-ième caractère.

C'est pour cela que strlen(serveurs[i]) et strcmp(serveurs[i], recherche) fonctionnent sans rien de plus : on leur donne une ligne, c'est-à-dire une chaîne.

28Construire un identifiant Moyen

Exercice 4. Demander un prénom puis un nom, construire une chaîne contenant le prénom, un _, puis le nom. Afficher l'identifiant et sa longueur. L'énoncé donne le résultat attendu : Jean_Dupont, longueur 11.

✅ Correction
C
#include <stdio.h>
#include <string.h>

int main(void)
{
    char prenom[50];
    char nom[50];
    char identifiant[101];

    printf("Prenom : ");
    scanf("%49s", prenom);
    printf("Nom : ");
    scanf("%49s", nom);

    strcpy(identifiant, prenom);
    strcat(identifiant, "_");
    strcat(identifiant, nom);

    printf("\nIdentifiant : %s\n", identifiant);
    printf("Longueur : %zu\n", strlen(identifiant));

    return 0;
}
sortie réelle — saisies : Jean puis Dupont
Prenom : Nom :
Identifiant : Jean_Dupont
Longueur : 11
🛠️ Un strcpy puis deux strcat

On copie d'abord — identifiant ne contient rien de sûr avant — puis on colle le reste. Faire trois strcat sur un tableau non initialisé collerait à la suite de ce qui s'y trouvait, c'est-à-dire n'importe quoi.

La taille : 50 + 1 + 50, plus le '\0' → [101]. Le résultat, 11 caractères, correspond exactement à ce que l'énoncé annonce.

29Le programme de contrôle, sans aucune saisie Moyen

Pour vérifier vos quatre programmes d'un coup. Les données sont écrites dans le code, il n'y a rien à taper : la sortie est donc comparable, et elle est vérifiée à chaque publication.

✅ Correction
C
#include <stdio.h>
#include <string.h>

int voyelles(const char *mot)
{
    int n = 0;
    size_t i;

    for (i = 0; i < strlen(mot); i++) {
        char c = mot[i];
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y'
         || c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || c == 'Y') {
            n++;
        }
    }
    return n;
}

int main(void)
{
    char serveurs[5][30] = {
        "SRV_WEB", "SRV_DNS", "SRV_BDD", "SRV_FICHIERS", "SRV_BACKUP"
    };
    char mot[] = "Anticonstitutionnellement";
    char nom1[] = "Dupont";
    char nom2[] = "Durand";
    char copie[50];
    char identifiant[101] = "Jean";
    int i, plus_long = 0, trouve = 0;

    printf("=== EXERCICE 1 : analyser un mot ===\n");
    printf("Mot              : %s\n", mot);
    printf("Longueur         : %zu\n", strlen(mot));
    printf("Premier caractere: %c\n", mot[0]);
    printf("Dernier caractere: %c\n", mot[strlen(mot) - 1]);
    printf("Voyelles         : %d\n", voyelles(mot));

    printf("\n=== EXERCICE 2 : comparer deux noms ===\n");
    printf("%s : %zu caracteres\n", nom1, strlen(nom1));
    printf("%s : %zu caracteres\n", nom2, strlen(nom2));
    printf("strcmp(\"%s\", \"%s\") = %d\n", nom1, nom2, strcmp(nom1, nom2));
    if (strcmp(nom1, nom2) == 0) {
        printf("Les deux noms sont identiques.\n");
    } else {
        printf("Les deux noms ne sont pas identiques.\n");
    }
    strcpy(copie, nom1);
    printf("Copie : %s\n", copie);

    printf("\n=== EXERCICE 3 : les cinq serveurs ===\n");
    for (i = 0; i < 5; i++) {
        printf("  %-13s %zu caracteres\n", serveurs[i], strlen(serveurs[i]));
        if (strlen(serveurs[i]) > strlen(serveurs[plus_long])) {
            plus_long = i;
        }
    }
    printf("Nom le plus long : %s\n", serveurs[plus_long]);
    for (i = 0; i < 5; i++) {
        if (strcmp(serveurs[i], "SRV_DNS") == 0) {
            trouve = 1;
        }
    }
    printf("Recherche de SRV_DNS : %s\n", trouve ? "trouve" : "introuvable");

    printf("\n=== EXERCICE 4 : construire un identifiant ===\n");
    strcat(identifiant, "_");
    strcat(identifiant, "Dupont");
    printf("Identifiant : %s\n", identifiant);
    printf("Longueur    : %zu\n", strlen(identifiant));

    return 0;
}
sortie
=== EXERCICE 1 : analyser un mot ===
Mot              : Anticonstitutionnellement
Longueur         : 25
Premier caractere: A
Dernier caractere: t
Voyelles         : 10

=== EXERCICE 2 : comparer deux noms ===
Dupont : 6 caracteres
Durand : 6 caracteres
strcmp("Dupont", "Durand") = -2
Les deux noms ne sont pas identiques.
Copie : Dupont

=== EXERCICE 3 : les cinq serveurs ===
  SRV_WEB       7 caracteres
  SRV_DNS       7 caracteres
  SRV_BDD       7 caracteres
  SRV_FICHIERS  12 caracteres
  SRV_BACKUP    10 caracteres
Nom le plus long : SRV_FICHIERS
Recherche de SRV_DNS : trouve

=== EXERCICE 4 : construire un identifiant ===
Identifiant : Jean_Dupont
Longueur    : 11
⚠️ strcmp rend −2 ici, pas −1

'p' vaut 112 et 'r' 114 : la différence est −2. Mais la norme ne garantit que le signe — une autre bibliothèque C pourrait rendre −1. On teste donc < 0, == 0 ou > 0, jamais une valeur précise.

⚡ Ce que ces trois TP font travailler

TP 2 — le langage

  • Exercice 1 — chaîne else if, et l'ordre des tests : le cas d'erreur d'abord.
  • Exercice 2 — accumulateur initialisé à 0, boucle for à nombre de tours connu.
  • Exercice 3 — switch sur des valeurs précises, un break par case.
  • Exercice 4 — % et / pour découper un nombre, while à nombre de tours inconnu.
  • Exercice 5 — do…while, parce qu'il faut au moins une saisie.
  • Exercice 6 — traduire un énoncé mathématique ligne par ligne.
  • Exercice 7 — extraire les chiffres d'un entier, et compter les arrangements.
  • Exercice 8 — lire du code exactement : le point-virgule qui vide une boucle, la division entière, ++j contre j++, et la valeur du compteur à la sortie.

TP 3 — fonctions et tableaux

  • Une fonction, une phrase sans « et ». Si la description en contient un, il y a deux fonctions.
  • (a + b) / 2 — les parenthèses, sinon la division passe avant l'addition.
  • (float) perdus / envoyes — sans la conversion, deux entiers donnent un entier, et le taux vaut 0.
  • 0 <= v && v <= 255 — l'écriture mathématique 0 <= v <= 255 compile et est toujours vraie.
  • %% pour afficher un pourcentage.
  • max = t[0], boucle à partir de i = 1 — partir de 0 est faux dès qu'une valeur est négative.
  • position = -1 pour dire « pas trouvé » : 0 est un indice valide.
  • La position, c'est l'indice : on compte 0 1 2 3 4, donc la cinquième valeur est à la position 4.
  • Un tableau passé à une fonction perd sa taille : on passe toujours n.
  • Mais la fonction peut le remplir : c'est pour cela que SaisirTableau() ne retourne rien.

TP 4 — les tableaux à deux dimensions

  • Une boucle dans une boucle, toujours. Ce qui change d'un exercice à l'autre, c'est laquelle est à l'extérieur.
  • « Par ligne » ou « par colonne » : l'énoncé le dit, il suffit de le lire. « Établies PAR un serveur » → la ligne. « Moyenne D'UN serveur » → la colonne.
  • L'accumulateur se remet à zéro au début de chaque ligne — pas avant la double boucle.
  • int t[][5] : la seconde taille ne s'omet jamais dans un paramètre de fonction.
  • Le maximum part de la première case, jamais de 0.
  • Retenir l'indice, pas la valeur : avec l'indice on retrouve tout le reste.
  • Le dernier élément d'un [3][4] est [2][3] — la taille moins un, dans chaque dimension.

Sources exploitées

  • TP2 — Langage C, le professeur, BTS CIEL 2026-2027 (version du 18/09/2026, 8 exercices)
  • Première version du même TP, du 18/09/2026 au matin (4 exercices) — conservée : les énoncés 1 à 4 y sont identiques
  • Cours « Algorithmique et programmation », chapitres 2 et 3
  • Sujet « TP 3 : les fonctions et les tableaux », neuf exercices avec leurs exemples d'exécution
  • Polycopié « Algorithmique et programmation », chapitre 4 — les fonctions
  • Sujet « TP 4 : les tableaux », trois exercices — matrice de connexions, relevés de températures, tentatives de connexion
  • Cours « Algorithmique et programmation » du 02/10/2026, chapitre 4 — les tableaux, section 3 : les tableaux à deux dimensions
  • Sujet « TP 5 : les pointeurs », quatre exercices — huit mesures au pointeur, saisie de taille inconnue, recherche d'une valeur, et un capteur avec calloc
  • Cours « Algorithmique et programmation » du 09/10/2026, chapitre 5 — les pointeurs
  • Sujet « TP 6 : les structures », sept exercices — un produit, un véhicule, un stock de cinq produits, deux fonctions, un capteur au pointeur, une bibliothèque allouée dynamiquement, et un équipement avec sa date d'achat

Les huit corrections ont été compilées avec cc -std=c99 -Wall puis exécutées. Les sorties annoncées sont celles obtenues, pas celles attendues.

Les neuf programmes publiés ici sont compilés et exécutés par verif-c.py à chaque contrôle, avec les saisies indiquées. Les valeurs affichées — 20.00, 12.00 Mo/s, 5.00 %, 22.4 °C, 102.88 Mb/s, 58.40 %, 11.50 — sont celles obtenues, et elles correspondent toutes à celles annoncées par le sujet.