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;
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... */ }
- Créer une action
- Augmenter la taille du tableau d'actions
- 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; }
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
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 = "";
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);
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 */ }
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; }
Très simplement
Code:
Personne init(void){ Personne p = {"", "", -1}; /* initialisation d'une personne */ return p; }
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; }
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