Programmation C
Structuration du code - Correction des exercices
Cours Exercices Correction des exercices

Exercice 1 Exercice 2 Exercice 3 Exercice 4
Exercice 5 Exercice 6 Exercice 7 Exercice 8

Exercice 1 (while)

#include <stdio.h>
#include <stdlib.h>

void main(void) {
  srand(0);
  int cpt = 1;
  while (rand() != 0) {
    cpt++;
  }
  printf("%12d\n", cpt);
}

04-Exercice1.c - 04-Exercice1.exe
       65830
  • RAS

Exercice 2 (while)

#include <stdio.h>
#include <stdlib.h>

void main(void) {
  srand(9);
  char c1 = 'a' + rand() % 26;
  char c2;
  while ((c2 = 'a' + rand() % 26) == c1);
  printf("%c %c\n", c1, c2);
  char c3;
  while (((c3 = 'a' + rand() % 26) == c1) || (c3 == c2));
  printf("%c %c %c\n", c1, c2, c3);
}

04-Exercice2.c - 04-Exercice2.exe
q p
q p b
  • Utilisation du égal d'affectation à une variable en tant qu'opérateur qui retourne la valeur affectée

Exercice 3 (do while)

#include <stdio.h>

const double PI = 3.141592653589793;

void main(void) {
  long long dividende = 22;
  long long diviseur = 7;
  double fraction = (double) dividende / diviseur;
  double delta = fabs(PI - fraction);
  printf("%8lld %8lld\n", dividende, diviseur);
  printf("%20.18lf %20.18lf\n", PI, fraction);
  printf("%20.18lf\n\n", delta);
  int v;
  double dInf;
  double dSup;
  do {
    diviseur++;
    v = (int) (diviseur * PI);
    double vInf = (double) v / diviseur;
    double vSup = (double) (v + 1) / diviseur;
    dInf = fabs(vInf - PI);
    dSup = vSup - PI;
  } while ((dInf >= delta) && (dSup >= delta) && (delta != 0));
  dividende = dInf < dSup ? v : v + 1;
  fraction = (double) dividende / diviseur;
  delta = fabs(PI - fraction);
  printf("%8lld %8lld\n", dividende, diviseur);
  printf("%20.18lf %20.18lf\n", PI, fraction);
  printf("%20.18lf\n", delta);
}

04-Exercice3.c - 04-Exercice3.exe
       22       7
3.141592653589793116 3.142857142857142794
0.001264489267349678

     179      57
3.141592653589793116 3.140350877192982448
0.001241776396810668
  • Attention, utilisation de l'opérateur conditionnel en fin d'algorithme pour arbitrer entre v et v+1 pour le choix du dividende

Exercice 4 (for)

#include <stdio.h>

const double PI = 3.141592653589793;

void main(void) {
  for (int n = 1; n <= 9; n++) {
    double pi1 = 0.0;
    for (int i = 1, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi1 += signe * 4.0 / i;
    }
    double pi2 = 3.0;
    for (int i = 2, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi2 += signe * 4.0 / (i * (i + 1LL) * (i + 2LL));
    }
    printf("%5d : %20.16lf %20.16lf : %20.16lf %20.16lf : %12.1lf\n", n
           , pi1
           , pi1 - PI
           , pi2
           , pi2 - PI
           , fabs(pi1 - PI) / fabs(pi2 - PI));
  }
  for (int n = 10; n <= 90; n += 10) {
    double pi1 = 0.0;
    for (int i = 1, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi1 += signe * 4.0 / i;
    }
    double pi2 = 3.0;
    for (int i = 2, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi2 += signe * 4.0 / (i * (i + 1LL) * (i + 2LL));
    }
    printf("%5d : %20.16lf %20.16lf : %20.16lf %20.16lf : %12.1lf\n", n
           , pi1
           , pi1 - PI
           , pi2
           , pi2 - PI
           , fabs(pi1 - PI) / fabs(pi2 - PI));
  }
  for (int n = 100; n <= 900; n += 100) {
    double pi1 = 0.0;
    for (int i = 1, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi1 += signe * 4.0 / i;
    }
    double pi2 = 3.0;
    for (int i = 2, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi2 += signe * 4.0 / (i * (i + 1LL) * (i + 2LL));
    }
    printf("%5d : %20.16lf %20.16lf : %20.16lf %20.16lf : %12.1lf\n", n
           , pi1
           , pi1 - PI
           , pi2
           , pi2 - PI
           , fabs(pi1 - PI) / fabs(pi2 - PI));
  }
  for (int n = 1000; n <= 10000; n += 1000) {
    double pi1 = 0.0;
    for (int i = 1, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi1 += signe * 4.0 / i;
    }
    double pi2 = 3.0;
    for (int i = 2, signe = 1; i <= 2 * n + 1; i += 2, signe = -signe) {
      pi2 += signe * 4.0 / (i * (i + 1LL) * (i + 2LL));
    }
    printf("%5d : %20.16lf %20.16lf : %20.16lf %20.16lf : %12.1lf\n", n
           , pi1
           , pi1 - PI
           , pi2
           , pi2 - PI
           , fabs(pi1 - PI) / fabs(pi2 - PI));
  }
}

04-Exercice4.c - 04-Exercice4.exe
...
  • Quatre for principaux pour itérer sur n sur les quatre intervalles [1,9], [10,90], [100, 900] et [1000,10000]
  • Deux for imbriqués dans chacun des quatre for principaux pour implanter les formules de calcul
  • Pour chaque n, deux valeurs estimées de PI calculées (une par formule) et comparées par affichage de la différence avec la "vraie" valeur (erreur d'estimation) et affichage du rapport entre les deux différences (détermination de la meilleure estimation)
  • Programmation sans fonction -> beaucoup de code dupliqué et peu d'expressivité à l'arrivée -> pas génial

Exercice 5 (if)

#include <stdio.h>
#include <stdlib.h>

int main(void) {
  srand(2224);
  {
    int v1 = rand() % 256;
    printf("%3d %2X\n", v1, v1);
    int chiffreUnites = v1 & 0b1111;   // ou v1 & 0x0F ou v1 % 16
    int chiffreDizaines = v1 >> 4;
    printf("%2d %2d\n", chiffreDizaines, chiffreUnites);
    if (chiffreDizaines < 10) {
      printf("%d", chiffreDizaines);
    }
    else {
      printf("%c", 'A' - 10 + chiffreDizaines);
    }
    if (chiffreUnites < 10) {
      printf("%d", chiffreUnites);
    }
    else {
      printf("%c", 'A' - 10 + chiffreUnites);
    }
    printf("\n\n");
  }
  {
    int v2 = 10000 + rand() % 90000;
    printf("%d\n", v2);
    int chiffreUnites = v2 % 10;
    int chiffreDizainesMilliers = v2 / 10000;
    printf("%d %d\n", chiffreUnites, chiffreDizainesMilliers);
    int palindrome = 0;
    if (chiffreUnites == chiffreDizainesMilliers) {
      int chiffreDizaines = (v2 / 10) % 10;
      int chiffreMilliers = (v2 / 1000) % 10;
      printf("%d %d\n", chiffreDizaines, chiffreMilliers);
      if (chiffreDizaines == chiffreMilliers) {
        palindrome = 1;
      }
    }
    if(palindrome == 1) {
      printf("%d est palindromique\n",v2);
    }
    else {
      printf("%d n'est pas palindromique\n",v2);
    }
  }
  return 0;
}

04-Exercice5.c - 04-Exercice5.exe
133 85
 8  5
85

34303
3 3
0 4
34303 n'est pas palindromique
  • RAS

Exercice 6 (switch)

#include <stdio.h>
#include <stdlib.h>

int main(void) {
  srand(204);
  char operation = 0x00;
  switch (rand() % 5) {
    case 0: {
      operation = '+';
      break;
    }
    case 1: {
      operation = '-';
      break;
    }
    case 2: {
      operation = '*';
      break;
    }
    case 3: {
      operation = '/';
      break;
    }
    case 4: {
      operation = '%';
      break;
    }
  }
  int v1 = 10 + rand() % 990;
  int v2 = 10 + rand() % 90;
  int resultat = -1;
  switch (operation) {
    case '+': {
      resultat = v1 + v2;
      break;
    }
    case '-': {
      resultat = v1 - v2;
      break;
    }
    case '*': {
      resultat = v1 * v2;
      break;
    }
    case '/': {
      resultat = v1 / v2;
      break;
    }
    case '%': {
      resultat = v1 % v2;
      break;
    }
  }
  if (operation != 0x00) {
    printf("%d %c %d = %d", v1, operation, v2, resultat);
  }
  else {
    printf("Probl�me !!!");
  }
  return 0;
}

04-Exercice6.c - 04-Exercice6.exe
988 % 31 = 27
  • RAS

Exercice 7 (fonctions)

#include <stdio.h>
#include <stdlib.h>

int myRand(void) {
  return rand() * (RAND_MAX + 1) + rand();
}

int randDansIntervalle1(int bi, int bf) {
  return bi + rand() % (bf - bi + 1);
}

int randDansIntervalle2(int bi, int bf) {
  return bi + myRand() % (bf - bi + 1);
}

int randDansIntervalle(int bi, int bf, int (*fonctionRand)(void)) {
  return bi + fonctionRand() % (bf - bi + 1);
}

double rand01(void) {
  return ((double) myRand() / (RAND_MAX + 1)) / (RAND_MAX + 1);
}

void tester1(int n) {
  int n5 = 0;
  int n6 = 0;
  int n7 = 0;
  int n8 = 0;
  int n9 = 0;
  int n10 = 0;
  for (int i = 0; i < n; i++) {
    int v = randDansIntervalle1(5, 10);
    switch (v) {
      case 5: {
        n5++;
        break;
      }
      case 6: {
        n6++;
        break;
      }
      case 7: {
        n7++;
        break;
      }
      case 8: {
        n8++;
        break;
      }
      case 9: {
        n9++;
        break;
      }
      case 10: {
        n10++;
        break;
      }
    }
  }
  printf("%7d %7d %7d %7d %7d %7d : %7d\n", n5, n6, n7, n8, n9, n10,
         n5 + n6 + n7 + n8 + n9 + n10);
  printf("%7.3lf %7.3lf %7.3lf %7.3lf %7.3lf %7.3lf\n",
         (double) n5 / n * 100.0,
         (double) n6 / n * 100.0,
         (double) n7 / n * 100.0,
         (double) n8 / n * 100.0,
         (double) n9 / n * 100.0,
         (double) n10 / n * 100.0);
}

void tester2(int n) {
  int n0 = 0;
  int n1 = 0;
  int n2 = 0;
  for (int i = 0; i < n; i++) {
    int v = randDansIntervalle1(0, 29999);
    if ((v >= 0) && (v <= 9999)) {
      n0++;
    }
    if ((v >= 10000) && (v <= 19999)) {
      n1++;
    }
    if ((v >= 20000) && (v <= 29999)) {
      n2++;
    }
  }
  printf("%7d %7d %7d %23s : %7d\n", n0, n1, n2, "", n0 + n1 + n2);
  printf("%7.3lf %7.3lf %7.3lf\n",
         (double) n0 / n * 100.0,
         (double) n1 / n * 100.0,
         (double) n2 / n * 100.0);
}

void tester3(int n) {
  int n0 = 0;
  int n1 = 0;
  int n2 = 0;
  for (int i = 0; i < n; i++) {
    int v = randDansIntervalle2(0, 29999);
    if ((v >= 0) && (v <= 9999)) {
      n0++;
    }
    if ((v >= 10000) && (v <= 19999)) {
      n1++;
    }
    if ((v >= 20000) && (v <= 29999)) {
      n2++;
    }
  }
  printf("%7d %7d %7d %23s : %7d\n", n0, n1, n2, "", n0 + n1 + n2);
  printf("%7.3lf %7.3lf %7.3lf\n",
         (double) n0 / n * 100.0,
         (double) n1 / n * 100.0,
         (double) n2 / n * 100.0);
}

void tester4(int n) {
  int n0 = 0;
  int n1 = 0;
  int n2 = 0;
  int n3 = 0;
  for (int i = 0; i < n; i++) {
    double v = rand01();
    if ((v >= 0) && (v < 0.25)) {
      n0++;
    }
    if ((v >= 0.25) && (v < 0.5)) {
      n1++;
    }
    if ((v >= 0.5) && (v < 0.75)) {
      n2++;
    }
    if ((v >= 0.75) && (v < 1.0)) {
      n3++;
    }
  }
  printf("%7d %7d %7d %7d %15s : %7d\n", n0, n1, n2, n3, "", n0 + n1 + n2 + n3);
  printf("%7.3lf %7.3lf %7.3lf %7.3lf\n",
         (double) n0 / n * 100.0,
         (double) n1 / n * 100.0,
         (double) n2 / n * 100.0,
         (double) n3 / n * 100.0);
}

int main(void) {
  srand(7);
  tester1(6000000);
  printf("\n");
  tester2(3000000);
  printf("\n");
  tester3(3000000);
  printf("\n");
  tester4(4000000);
  return 0;
}

04-Exercice7.c - 04-Exercice7.exe
 999746 1000760 1000581 1000044  999677  999192 : 6000000
 16.662  16.679  16.676  16.667  16.661  16.653

1169614  914524  915862                         : 3000000
 38.987  30.484  30.529

 999744 1001346  998910                         : 3000000
 33.325  33.378  33.297

 998323  999903 1000850 1000924                 : 4000000
 24.958  24.998  25.021  25.023
  • Fonction myRand : implantation du calcul proposé dans l'énoncé
  • Fonctions randDansIntervalle1 et randDansIntervalle2 : implantation du tirage au sort dans un intervalle en utilisant la fonction rand standard pour randDansIntervalle1 et et la fonction myRand pour randDansIntervalle2
  • Fonction rand01 : implantation du calcul d'une valeur tirée au sort dans l'intervalle [0.0, 1.0[ en divisant un nombre entier tiré au sort dans l'intervalle [0,(RAND_MAX+1)2-1] par (RAND_MAX+1)2.
  • Développement de quatre fonctions de test exécutées par la fonction main
    Passage en paramètre à chacune de ces fonctions du nombre de nombres aléatoires qu'elle doit générer et analyser
    Affichage par chacune des fonctions des effectifs trouvés, du total des effectifs trouvés (qui doit être égal au nombre de nombres aléatoires générés) et des pourcentages de nombres trouvés
    • tester1 : test de randDansIntervalle1 (qui utilise la fonction rand standard) sur 6 millions de tirages
      La répartition semble ne pas poser de problème avec des pourcentages voisins de 16.667%.
    • tester2 : test de randDansIntervalle1 (qui utilise la fonction rand standard) sur 3 millions de tirages
      La répartition pose un problème. On s'attend à trouver des valeurs plus proches de 1 million que celles trouvées. Les pourcentages sont très louches. Pourquoi ne sont-ils pas uniformes ?
    • tester3 : test de randDansIntervalle2 (qui utilise la fonction myRand) sur 3 millions de tirages
      La répartition semble ne pas poser de problème avec des pourcentages voisins de 33.333%.
    • tester4 : test de rand01 (qui utilise la fonction myRand) sur 4 millions de tirages
      La répartition semble ne pas poser de problème avec des pourcentages voisins de 25.0%.

Exercice 8 (fonctions)

#include <stdio.h>

int resoudreEquationSecondDegre(double a, double b, double c, double* x1, double* x2) {
  double delta = b * b - 4.0 * a * c;
  if (delta < 0.0) {
    return 0;
  }
  else {
    if (delta == 0.0) {
      *x1 = -b / (2.0 * a);
      return 1;
    }
    else {
      *x1 = (-b - sqrt(delta)) / (2.0 * a);
      *x2 = (-b + sqrt(delta)) / (2.0 * a);
      return 2;
    }
  }
}

void tester(double a, double b, double c) {
  double x1;
  double x2;
  int nb = resoudreEquationSecondDegre(a, b, c, &x1, &x2);
  switch (nb) {
    case 0: {
      printf("L'equation %.3lfx2%+.3lfx%+.3lf n'a pas de racine reelle\n", a, b, c);
      break;
    }
    case 1: {
      printf("L'equation %.3lfx2%+.3lfx%+.3lf a une racine reelle : %lf\n", a, b, c, x1);
      break;
    }
    case 2: {
      printf("L'equation %.3lfx2%+.3lfx%+.3lf a deux racines reelles : %lf et %lf\n", a, b, c, x1, x2);
      break;
    }
  }
}

int main(void) {
  tester(2.0, -3.1, 2.1);
  tester(2.0, 4.0, 2.0);
  tester(-2.0, 5.0, -2.0);
  return 0;
}

04-Exercice8.c - 04-Exercice8.exe
L'equation 2.000x2-3.100x+2.100 n'a pas de racine reelle
L'equation 2.000x2+4.000x+2.000 a une racine reelle : -1.000000
L'equation -2.000x2+5.000x-2.000 a deux racines reelles : 2.000000 et 0.500000
  • Développement d'une fonction à retour de type int : le nombre de racines trouvées qui pourra être 0, 1 ou 2
  • Développement d'une fonction possédant 5 paramètres
    • le coefficient a de type double
    • le coefficient b de type double
    • le coefficient c de type double
    • un premier pointeur sur double permettant de donner l'adresse de la variable à remplir pour donner la valeur de la racine s'il n'y en a qu'une, la valeur de la première racine s'il y en a deux
    • un second pointeur sur double permettant de donner l'adresse de la variable à remplir pour donner la valeur de la seconde racine s'il y en a deux
  • Lors de l'appel à la fonction resoudreEquationSecondDegre
    • Passage des adresses des deux variables de type double destinées à recevoir les valeurs des racines s'il y en a
    • Récupération en retour de fonction du nombre de racines
  • Nombre de racines stocké dans une variable utilisée ensuite dans un switch pour faire les affichages
  • Placement du test complet dans une fonction ad hoc utilisée trois fois dans le programme principal avec les jeux de paramètres (a,b,c) de l'énoncé