Informations

Date limite Pas de date limite
Limite de soumission Pas de limite

Etiquettes

Se connecter

[10.1] Rappel des concepts [Obligatoire]

La construction de programmes

Jusqu'à présent, vous avez appris la base de la programmation en C grâce à une série de petits exercices. Cependant, ces exercices étaient relativement simples et guidés par des consignes précises. Il est toutefois important de savoir comment construire un programme plus conséquent en partant juste d'un énoncé en français. Pour cela, il faut suivre une démarche rigoureuse en plusieurs étapes :

  1. Analyse de l'énoncé : Lire attentivement l'énoncé pour comprendre les exigences et les contraintes du programme à développer.
  2. Définition des structures de données : Définir les structures de données nécessaires pour représenter les informations de l'énoncé dans un format exploitable par le programme.
  3. Décomposition en sous-problèmes : Diviser le problème global en sous-problèmes de plus petite taille. Chaque sous-problème doit être plus simple à résoudre et doit contribuer à la solution globale.
  4. Spécification des fonctions : Pour chaque sous-problème, définir les fonctions nécessaires pour le résoudre. Il faut spécifier les entrées, les sorties et le comportement attendu de chaque fonction.
  5. Division en modules : Organiser les fonctions et structures en modules logiques si nécessaire. Chaque module doit regrouper des fonctions liées et structures entre elles par leur fonctionnalité.
  6. Implémentation : Écrire le code C des fonctions et du programme principal. Il est important de respecter les bonnes pratiques de programmation vues jusqu'à présent.
  7. Vérification et validation : Tester le programme pour s'assurer qu'il fonctionne correctement et répond aux exigences de l'énoncé.

Exemple : Le Jardin Virtuel

Pour illustrer cette démarche, considérons l'exemple d'un programme permettant de gérer une version virtuelle de son jardin afin de pouvoir suivre l'état de croissance de ses plantes et de ne pas oublier quelles plantes ont été plantées.

Le programme doit permettre de créer son jardin qui sera forcément rectangulaire et vide au départ. Ensuite, on doit être capable de réaliser plusieurs actions :

  • Ajouter une plante en précisant son type (fleur, légume, arbre, etc.), sa date de plantation et son état de croissance (germination, croissance et floraison).
  • Changer l'état de croissance d'une plante existante.
  • Supprimer une plante.
  • Afficher l'état actuel du jardin.

Après avoir analysé l'énoncé (étape 1), on peut réfléchir aux structures de données nécessaires (étape 2). Plusieurs structures de données sont possibles mais ici, on peut remarquer que selon l'énoncé, la taille du jardin est rectangulaire et n'a pas besoin de changer. On peut donc utiliser un tableau à deux dimensions pour représenter le jardin. On remarque cependant que le jardin est vide au départ donc on peut en conclure que chaque case du tableau peut contenir soit une plante, soit rien. Pour représenter une plante, le plus simple est de créer une structure plante contenant les informations nécessaires. On pourrait aussi créer une énumération pour représenter les différents états de croissance puisqu'ils sont limités et connus à l'avance. Le seul soucis vient du fait qu'on peut avoir des cases vides dans le jardin. On pourrait avoir un champ dans la structure plante pour indiquer si la plante est présente ou non mais cela ne serait pas très propre. Une meilleur solution serait plutôt d'utiliser un tableau à deux dimensions de pointeurs vers des structures plante. Ainsi, si une case est vide, le pointeur sera NULL et s'il y a une plante, le pointeur pointera vers une structure plante correctement remplie. On aurait donc les structures de données suivantes :

enum etat_croissance {
    GERMINATION,
    CROISSANCE,
    FLORAISON
};

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

struct plante {
    char *type;
    struct date date_plantation;
    enum etat_croissance etat;
};

typedef struct plante ***jardin;  // 2 pointeurs pour le tableau 2D et 1 pointeur pour la plante

Maintenant, on peut décomposer le problème en sous-problèmes (étape 3). Ici, on peut identifier les sous-problèmes suivants :

  1. Allouer le jardin.

  2. Désallouer le jardin.

  3. Ajouter une plante.

  4. Changer l'état de croissance d'une plante.

  5. Supprimer une plante.

  6. Afficher l'état actuel du jardin.

  7. Gérer le menu principal pour permettre à l'utilisateur de choisir les actions à réaliser.

    1. Gérer l'entrée utilisateur pour choisir une action.
    2. Gérer le sous-menu pour demander les informations nécessaires pour ajouter une plante.
    3. Gérer le sous-menu pour demander les informations nécessaires pour changer l'état de croissance d'une plante.
    4. Gérer le sous-menu pour demander les informations nécessaires pour supprimer une plante.

Ensuite, on peut spécifier les fonctions nécessaires pour chaque sous-problème (étape 4). Par exemple, pour le sous-problème "Ajouter une plante", on pourrait avoir la fonction suivante :

// PRE: le jardin est initialisé de taille taille_x * taille_y et (x, y) sont des coordonnées valides dans le jardin
// POST: une nouvelle plante est ajoutée au jardin aux coordonnées (x, y) avec le type, la date de plantation et l'état de croissance spécifiés
void ajouter_plante(jardin mon_jardin, int taille_x, int taille_y, int x, int y, char *type, struct date date_plantation, enum etat_croissance etat);

Après cela, on peut organiser les fonctions en modules logiques (étape 5). Ici, on pourrait avoir l'organisation suivante :

  • Module jardin : Contient les fonctions et structures liées à la gestion du jardin et des plantes (initialisation, ajout, modification, suppression, affichage).
  • Module menu : Contient les fonctions liées à la gestion du menu principal et des actions utilisateur.
  • Programme principal : Contient la fonction main qui initialise le jardin et gère la boucle principale du menu.

Enfin, on peut implémenter le code C des fonctions et du programme principal (étape 6) en respectant les bonnes pratiques de programmation.

Une fois le code implémenté, il est crucial de vérifier et valider le programme (étape 7) en l'exécutant avec différents scénarios de test pour s'assurer qu'il fonctionne correctement et répond aux exigences de l'énoncé. Par exemple, on peut tester que, depuis un jardin vide, on peut ajouter une plante à une position vide, qu'on peut la supprimer et puis qu'en affichant le jardin, on retrouve bien un jardin vide, etc.


Question 1: Structures de données

Un même énoncé peut être représenté par plusieurs structures de données différentes ?

Question 2: Décomposition en sous-problèmes

La décomposition en sous-problèmes permet de :

Question 3: Division en modules

Dans quel cas est-il pertinent de diviser un programme en plusieurs modules ?

Question 4: Vérification et validation

Pourquoi est-il important de vérifier et valider un programme après son implémentation ?