Annonce

Réduire
Aucune annonce.

Cours langage C n°16 - Allocation dynamique et Structure

Réduire
Ceci est une discussion importante.
X
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • Cours langage C n°16 - Allocation dynamique et Structure

    Allocation dynamique + Structure


    PRÉREQUIS

    Cours n°7 - Adresses mémoire et pointeurs
    Cours n°13 - Définition de synonymes
    Cours n°15 - Allocation dynamique

    PROBLÉMATIQUE

    Vous êtes dans une banque et on vous demande de créer un gestionnaire de comptes clients. Pour cela il nous faudra pouvoir y créer un compte dont les différents attributs seront:
    • Le nom du client
    • Le prénom du client
    • L'id du client
    • La somme courante
    • Un tableau représentant les différentes actions sur le compte (achat, crédit, ...)


    Une banque contient donc plusieurs comptes... avec ses attributs
    • Liste des comptes
    • Nombre de comptes
    • Nombre de comptes dans le moins
    • Nombre de comptes dans le plus
    • Somme totale des sommes courantes de chaque compte


    Version, vous l'admettrez, très simplifiée

    L'objet Compte

    On est bien d'accord que pour avoir tout ces renseignements, il nous faut créer des actions, dont les attributs seront
    • G/D (gains ou dépenses)
    • valeur du gain ou dépense
    • Date
    • Raison


    On va donc avoir un objet Compte qui sera ressemblant à

    Code:
    typedef enum{
        G, /* Gain */
        D /* Dépense */
    } type;
    
    typedef struct{
        int jour;
        int mois;
        int annee;
    } Date;
    
    typedef struct{
        type t; /* gain ou dépense */
        double valeur; /* valeur du gain ou de la dépense */
        Date date;
        char raison[30]; /* raison du gain ou dépense - pas plus de 30 caractères */
    } Action;
    
    typedef struct{
        char *nom;
        char *prenom;
        char ID[12]; /* ID du détenteur du compte */
        double somme; /* somme courante */
        Action *actions;
        long int nbreActions;
    } Compte;
    Comme on le voit ça se complique, ( eh on est au cours n°16, hein ), il y a déjà pas mal de structures, mais ça se fait tout seul si l'organisation rigoureuse est au rendez-vous !

    De loin on voit tout de suite ce qui est embêtant ! C'est la gestion des différentes actions, où il va falloir
    Ajouter des actions
    Supprimer des actions (en cas d'erreur)

    et encore on ne gère pas les ordres des actions selon les dates par exemple... bref ça peut devenir très compliqué !

    Création de la liste d'actions

    Eh bien vous l'aurez deviné, cette partie est lourde car on ne connaît pas d'avance le nombre total d'actions (donc la taille de actions) sur la durée de vie d'un compte, et donc on est obligé d'ajouter au fur et à mesure une action dans la liste d'actions, ce qui impose l'allocation dynamique.

    Pour ajouter une action à un compte, la logique voudrait:

    Code:
    /* Ajouter une action sur le compte */
    void ajouterAction(Compte c){
        Action *a = NULL;
        Action *action = CreerAction(type t, Date d, const char *raison, double v); /* création d'une action sur le compte */
        a = realloc(c.actions, (c.nbreActions + 1) * sizeof(Action));
        if (a != NULL){
            c.actions = a; /* c.actions reprend en mémoire la nouvelle mémoire allouée a */
            c.actions[nbreActions-1] = action; /* Ajout de l'action dans la liste des actions */
            c.nbreActions += 1; /* Ne pas oublier d'ajouter 1 au nombre d'actions totales */
            /* suite du code concernant les sommes à calculer, etc... */
    }
    En fait la logique pour vous n'est pas le code, mais le principe, qui est si on résume
    1. Créer une action
    2. Augmenter la taille du tableau d'actions
    3. Ajouter l'action


    Warf, c'est quoi ce realloc ?

    Mieux vaut vous le présenter sur un cas pratique, vous l'aurez deviné, ça permet de réallouer plus de mémoire. Vous allouez, mais vous vous rendez compte que ce n'est pas suffisant, pas grave, on réalloue de la mémoire de la taille d'une Action x (nbreActions+1) dans notre cas.

    Difficile je sais, va falloir s'entraîner ! Rien de tel pour cela que de regarder des petits exemples

    Il ne vous reste plus qu'à avoir votre propre réflexion pour créer votre logiciel bancaire

    CREER UN TABLEAU D'OBJETS DYNAMIQUEMENT

    Pour créer un tableau dynamique d'un objet, nous allons utiliser malloc et sizeof...
    • malloc permettant d'allouer de la mémoire
    • sizeof permettant de déterminer la taille de l'objet


    ainsi en déterminant le nombre d'objets à créer on pourra créer un tableau d'objets.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct{
    
        char Prenom[50];
        char Nom[50];
        int age;
    
    } Personne;
    
    Personne *creer(int n);
    
    int main(void){
    
        int nbPersonnes = 5, i;
        Personne *tab = creer(nbPersonnes); /* création de 5 personnes */
    
        for (i=0; i<nbPersonnes; i++)
            printf("Initialisation personne n°%d -> Nom:%s, Prénom:%s, age:%d\n", i, tab[i].Nom, tab[i].Prenom, tab[i].age);
    
        free(tab); /* Ne pas oublier de supprimer le tableau alloué en fin de programme */
    
        return 0;
    }
    
    Personne *creer(int n){
    
        int i;
        Personne *tableauPersonnes = malloc(sizeof(Personne) * n);
    
    
        for (i=0; i<n; i++){
            strcpy(tableauPersonnes[i].Prenom, "");
            strcpy(tableauPersonnes[i].Nom, "");
            tableauPersonnes[i].age = -1;
        }
    
        return tableauPersonnes;
    }
    Ce qui donne

    Code:
    Initialisation personne n°0 -> Nom:, Prénom:, age:-1
    Initialisation personne n°1 -> Nom:, Prénom:, age:-1
    Initialisation personne n°2 -> Nom:, Prénom:, age:-1
    Initialisation personne n°3 -> Nom:, Prénom:, age:-1
    Initialisation personne n°4 -> Nom:, Prénom:, age:-1
    Normal car nous avons initialisé les noms et prénoms des personnes à "" et l'âge des personnes à -1.
    Vous remarquerez aussi l'utilisation de strcpy, qui nous permet de copier un tableau de caractères dans les règles, vous n'avez pas le droit de faire cela par exemple.
    Code:
    tableauPersonnes[i].Nom = "";
    AJOUTER UN OBJET DANS UN TABLEAU D'OBJETS

    Pour cela on doit modifier la taille du tableau d'objets, et pour cela on utilisera realloc !

    La signature de cette fonction est la suivante

    Code:
    void* realloc (void* ptr, size_t size);
    Comme on peut le voir, realloc retourne une nouvelle adresse, il faudra donc ne jamais oublié de réassigner l'ancienne adresse à la nouvelle. Qui puis est on modifie le tableau, il faut donc avoir l'adresse du tableau en paramètre de fonction, ce qui impose l'ajout d'une étoile

    Code:
    void ajouterPersonne(Personne **tableau, int taille){
    
        Personne *p;
        p = realloc(*tableau, sizeof(Personne) * taille); /* taille étant la nouvelle taille à allouer */
    
        if (p != NULL) *tableau = p; /* important, assigner l'adresse résultante de realloc à l'adresse du tableau */
    }
    Ce qui s'utiliserait de cette manière

    Code:
    int main(void){
    
        int nbPersonnes = 5, i;
        Personne *tab = creer(nbPersonnes); /* création de 5 personnes */
    
        ajouterPersonne(&tab, nbPersonnes+1); /* allocation supplémentaire pour une nouvelle personne */
    
        tab[nbPersonnes] = ...; /* initialiser la nouvelle personne créée */
    
        for (i=0; i<nbPersonnes+1; i++)
            printf("Initialisation personne n°%d -> Nom:%s, Prénom:%s, age:%d\n", i, tab[i].Nom, tab[i].Prenom, tab[i].age);
    
        free(tab); /* Ne pas oublier de supprimer le tableau alloué en fin de programme */
    
        return 0;
    }
    Ce qu'il y a entre point de suspension ... c'est la fonction manquante qui pourrait être l'initialisation d'une personne.

    Très simplement

    Code:
    Personne init(void){
    
        Personne p = {"", "", -1}; /* initialisation d'une personne */
    
        return p;
    }
    Ce qui simplifierait la fonction creer

    Code:
    Personne *creer(int n){
    
        int i;
        Personne *tableau = malloc(sizeof(Personne) * n);
    
    
        for (i=0; i<n; i++)
            tableau[i] = init(); /* initialisation de chaque personne */
    
        return tableau;
    }
    EXERCICE

    1) Créer une structure dont l'alias sera nommé Liste comportant une liste d'entiers nommée maListe, dont on ne connaît pas le nombre d'éléments par avance, et le nombre d'éléments courant de la liste.
    2) Créer une fonction listInit, prenant en paramètre un entier représentant le nombre d'éléments, capacité totale de maListe.
    3) Créer une fonction ajouterValeur, prenant en paramètre la valeur à ajouter. Tous les 5 éléments ajoutés, on ajoutera 5 éléments à la capacité totale de maListe (via realloc)

    Merci de m'avoir lu et à bientôt pour le prochain cours
    Dernière modification par fred, 01 juillet 2015, 13h46.
Chargement...
X