Exercices corrigés td 2 algorithmique et programmation 2 ave

Exercices corrigés td 2 algorithmique et programmation 2 ave

Télécharger PDF

Département d’Informatique

Module I132 : Algorithmique et programmation 2

Parcours MIP (S3) - 22 mars 2020

Professeur S. ANTER - TD N° 2

Énoncé des Exercices

Exercice 1 : Manipulation de pointeurs et tableaux

Soit le programme C suivant :

1 #include <stdio.h>
2 #define N 10
3 main() {
4   int suite[N], *p;
5   *suite = 0;
6   p = suite + 1;
7   do {
8     *p = *(p - 1) + 5;
9     p++;
10  } while (p < suite + N);
11
12  for (p = suite; p < suite + N; p++)
13    printf("%d ", *p);
14 }
  1. Quels résultats fournira ce programme ?
  2. Écrire un programme réalisant exactement la même chose, en utilisant, à la place du formalisme pointeur, le formalisme tableau.

Exercice 2 : Opérations sur les pointeurs

Compléter le tableau ci-dessous en donnant les valeurs des différentes variables a, b, c, p et q pour chaque instruction.

1 main() {
2   int a=1, b=2, c=3;
3   int *p, *q;
4   p = &a;
5   q = &c;
6   *p = *q;
7   (*q)++;
8   p = q;
9   q = &b;
10  *p -= *q;
11  ++(*q);
12  *p *= *q;
13  ++(*q);
14  a = *q * *p;
15  p = &a;
16  *q = *p /= *q;
17 }

Tableau à compléter :

a b c p q
initialisation 1 2 3 - -
p = &a 1 2 3 &a -
q = &c
*p = *q
(*q)++
p = q
q = &b
*p -= *q
++(*q)
*p *= *q
++(*q)
a = *q * *p
p = &a
*q = *p /= *q 6 6 6 &a &b

Exercice 3 : Fonctions de gestion de notes

  1. Écrire la fonction void lire(float* notes, int n) permettant de remplir le tableau notes par les notes de n étudiants (les notes devront être comprises entre 0 et 20).
  2. Écrire la fonction void afficher(float* notes, int n) permettant d’afficher le tableau des notes.
    • en utilisant le formalisme tableau.
    • en utilisant le formalisme pointeur.
  3. Écrire la fonction float maximum(float* notes, int n) renvoyant l’élément maximum du tableau.
  4. Écrire la fonction int indice_max(float* notes, int n) renvoyant l’indice de l’élément maximum du tableau.
  5. En utilisant le formalisme pointeur, écrire la fonction int valide(float* notes, int n) renvoyant le nombre de notes supérieures à 10.
  6. Écrire la fonction float moyenne(float* notes, int n) renvoyant la moyenne des notes.
  7. Écrire la fonction void trier(float* notes) permettant de trier le tableau par ordre décroissant des notes.
  8. En utilisant la recherche dichotomique, écrire la fonction int existe(float* notes, float x, int n) renvoyant 1 si x existe dans le tableau notes et 0 sinon.
  9. Écrire le programme principal (main) de test.

Corrigé des Exercices

Corrigé Exercice 1

  1. Les résultats fournis par le programme sont une suite arithmétique de raison 5, commençant à 0.
  2. 0 5 10 15 20 25 30 35 40 45

  3. Programme réalisant la même chose avec le formalisme tableau :
  4. 1 #include <stdio.h>
    2 #define N 10
    3 main() {
    4   int suite[N], i;
    5   suite[0] = 0;
    6   for (i = 1; i < N; i++) {
    7     suite[i] = suite[i - 1] + 5;
    8   }
    9
    10  for (i = 0; i < N; i++)
    11    printf("%d ", suite[i]);
    12 }

    Ce programme illustre l'équivalence entre l'accès aux éléments d'un tableau via un indice (suite[i]) et via l'arithmétique de pointeurs (*(p - 1) ou suite + i).

Corrigé Exercice 2

Voici le tableau complété avec les valeurs des variables après chaque instruction. Les adresses des variables `a`, `b`, `c` sont représentées par `&a`, `&b`, `&c` respectivement.

Instruction a b c p q
initialisation 1 2 3 - -
p = &a 1 2 3 &a -
q = &c 1 2 3 &a &c
*p = *q 3 2 3 &a &c
(*q)++ 3 2 4 &a &c
p = q 3 2 4 &c &c
q = &b 3 2 4 &c &b
*p -= *q 3 2 2 &c &b
++(*q) 3 3 2 &c &b
*p *= *q 3 3 6 &c &b
++(*q) 3 4 6 &c &b
a = *q * *p 24 4 6 &a &b
p = &a 24 4 6 &a &b
*q = *p /= *q 6 6 6 &a &b

Cet exercice met en évidence les concepts fondamentaux des pointeurs en C : l'affectation d'adresses (p = &a), la déréférencement (*p), l'affectation de valeurs via un pointeur (*p = *q), et l'arithmétique de pointeurs implicite lors des affectations (p = q).

Corrigé Exercice 3

#include <stdio.h>
#define N 5 // N est défini ici pour l'exemple de main()

// 1. Fonction pour lire les notes
void lire(float *notes, int n) {
  int i;
  for (i = 0; i < n; i++) {
    do {
      printf("Notes[%d]= ", i);
      scanf("%f", &notes[i]);
    } while (notes[i] < 0 || notes[i] > 20);
  }
}

// 2. Fonction pour afficher les notes (formalisme tableau)
void afficherT(float *notes, int n) {
  int i;
  for (i = 0; i < n; i++)
    printf("%.2f ", notes[i]);
}

// 2. Fonction pour afficher les notes (formalisme pointeur)
void afficherP(float *notes, int n) {
  float *p;
  for (p = notes; p < notes + n; p++)
    printf("%.2f ", *p);
}

// 3. Fonction pour trouver le maximum des notes
float maximum(float *notes, int n) {
  int i;
  float m;
  m = notes[0];
  for (i = 1; i < n; i++)
    if (notes[i] > m)
      m = notes[i];
  return m;
}

// 4. Fonction pour trouver l'indice du maximum
int indice_max(float *notes, int n) {
  int i, k;
  k = 0;
  for (i = 1; i < n; i++)
    if (notes[i] > notes[k])
      k = i;
  return k;
}

// 5. Fonction pour compter les notes valides (supérieures à 10) - Formalisme pointeur
int valide(float *notes, int n) {
  int s = 0;
  float *p;
  for (p = notes; p < notes + n; p++)
    if (*p > 10)
      s++;
  return s;
}

// 6. Fonction pour calculer la moyenne des notes
float moyenne(float *notes, int n) {
  int i;
  float s = 0;
  for (i = 0; i < n; i++)
    s += notes[i];
  return s / n;
}

// 7. La fonction de tri (trier par ordre décroissant) n'est pas incluse dans le corrigé fourni.

// 8. Fonction pour vérifier si une note existe (implémentation de recherche linéaire)
// Note: L'énoncé demandait une recherche dichotomique, mais la solution fournie est une recherche linéaire.
int existe(float *notes, float x, int n) {
  int i;
  for (i = 0; i < n; i++)
    if (notes[i] == x)
      return 1;
  return 0;
}

// 9. Programme principal (main) de test
main() {
  float notes[N], x; // N est défini à 5 pour cet exemple

  lire(notes, N);

  printf("\nAffichage avec formalisme tableau: ");
  afficherT(notes, N);
  printf("\n");

  printf("Affichage avec formalisme pointeur: ");
  afficherP(notes, N);
  printf("\n");

  printf("Maximum = %.2f\n", maximum(notes, N));

  printf("Indice max = %d\n", indice_max(notes, N));

  printf("Moyenne = %.2f\n", moyenne(notes, N));

  printf("Entrer une valeur a rechercher (x): ");
  scanf("%f", &x);

  if (existe(notes, x, N))
    printf("%.2f existe dans le tableau.\n", x);
  else
    printf("%.2f n'existe pas dans le tableau.\n", x);
}

Ce corrigé fournit des implémentations pour la plupart des fonctions demandées. Il est important de noter que la fonction trier (tri décroissant) n'a pas été incluse dans la solution originale et que la fonction existe implémente une recherche linéaire plutôt qu'une recherche dichotomique, bien que cette dernière aurait nécessité que le tableau soit préalablement trié pour fonctionner efficacement.

Foire Aux Questions (FAQ)

Quelle est la différence entre le formalisme tableau et le formalisme pointeur en C ?

En C, un nom de tableau est souvent traité comme un pointeur constant vers son premier élément. Ainsi, tableau[i] est équivalent à *(tableau + i). Le formalisme tableau (tableau[i]) est généralement plus lisible et préféré pour l'accès indexé. Le formalisme pointeur (*(pointeur + i) ou pointeur[i] si le pointeur pointe vers le début d'une séquence) est plus souple et permet des opérations d'arithmétique de pointeurs, utile dans certaines optimisations ou algorithmes.

Pourquoi utilise-t-on le déréférencement (*p) en C ?

Le déréférencement, symbolisé par l'astérisque (*) devant un nom de pointeur (par exemple, *p), permet d'accéder à la valeur stockée à l'adresse mémoire indiquée par ce pointeur. Sans le déréférencement, p représenterait l'adresse mémoire elle-même, tandis que *p représente le contenu de cette adresse. C'est essentiel pour lire ou modifier les données vers lesquelles un pointeur "pointe".

Quels sont les avantages d'utiliser des fonctions pour manipuler des tableaux de données ?

L'utilisation de fonctions pour manipuler des tableaux, comme démontré dans l'Exercice 3, offre plusieurs avantages :

  • Modularité : Chaque fonction a une tâche spécifique (lire, afficher, calculer la moyenne), ce qui rend le code plus organisé.
  • Réutilisabilité : Les fonctions peuvent être appelées plusieurs fois avec différents tableaux ou paramètres, évitant la répétition de code.
  • Maintenance simplifiée : Les erreurs peuvent être isolées et corrigées plus facilement dans une fonction spécifique.
  • Clarté : Le programme principal (main) devient plus simple à lire car il se contente d'appeler les fonctions pertinentes.

Partagez vos remarques, questions ou propositions d'amélioration ici...

Enregistrer un commentaire (0)
Plus récente Plus ancienne

Publicité 1

Publicité 2