1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2013
    Messages : 45
    Points : 25
    Points
    25

    Par défaut Projet d'application et gestion des adresses de pointeurs

    Bonjour,


    Dans le cadre de mes cours (du soir), j'ai proposé a mon prof de pousser un exercice un peu plus loin que ce qui était demandé, et d'en faire une "vrai" application en y mettant tout ce que j'avais appris juqu'à maintenant.
    C'est la première fois que je n'ai pas de consigne pour réaliser mon projet et ou je dois commencer depuis le début, notamment la phase de design.

    Je me suis lancé dans la réalisation d'un programme qui imite le fonctionnement d'une application de messagerie (type Msn Messenger, ou SMS) en essayant de respecter le modèle MVC, le tout via des listes chainée (User -> contact -> msg) dans le modèle.

    Donc, je suis parti sur l'idée de considérer mon main comme un prg externe qui fait appel a une sorte d'API que mon controller fourni au main pour exécuter certaines fonctions de base : ajout, effacer, sélectionner, afficher (des user, contact ou msg).

    La ou je j'ai un peu de mal, c'est concernant la gestion des adresses de pointeurs qui vont contenir les listes chainées.
    Par exemple, j'appelle le module de gestion de la bdd (sous forme de liste chainée) via la controler. Le modèle va effectuer les opérations demandée sur la bdd, et fournir un résultat.
    Mais ou et comment est ce que je stocke les variables contenant les adresses de mes listes chainées (bdd) d'un appel a l'autre??
    Est ce que je dois déclarer des variables static dans les fonctions du modèle, ou est ce que je dois les renvoyer dans le controller?? Et les stocker dans, par ex, une structure et renvoyé a chaque fois au modèle l'adresse de la liste?!

    De même, j'ai un module "core" qui contiendra un module de gestion des erreurs qui seront stockée dans une liste chainée.. une fois une erreur ajoutée a la liste.. ou est ce que je "stocke" l'adresse de la liste??

    J'avoue que je suis vraiment confus par cette notion de stockage d'adresse..


    J'ai fait un schéma pour m'aider a y voir clair dans la structure de mon prg.
    C'est ma première tentative de réaliser un prg complet, donc soyez conciliant
    https://www.lucidchart.com/invitatio...4-6f2e7040c216

  2. #2
    Membre expert
    Inscrit en
    mars 2005
    Messages
    1 123
    Détails du profil
    Informations forums :
    Inscription : mars 2005
    Messages : 1 123
    Points : 3 286
    Points
    3 286

    Par défaut

    Pour garder trace du contexte (l'état de ton système), tu as deux solutions :

    • déclarer les variables d'état dans la portée globale ;
    • fournir des fonctions de création et de destruction de contexte et passer les objets initialisés par la bibliothèque (possiblement opaques) à chaque appel de traitement.


    En plus d'avantages en termes de lisibilité et de sécurité, la seconde solution rend ta bibliothèque ré-entrante : les appels ne modifient pas l'état global et peuvent être enchaînés dans n'importe quel ordre, depuis n'importe quel thread, pour peu qu'ils opèrent sur des contextes différents.

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    5 928
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 5 928
    Points : 16 386
    Points
    16 386
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par Dunkhan Voir le message
    Mais ou et comment est ce que je stocke les variables contenant les adresses de mes listes chainées (bdd) d'un appel a l'autre??
    J'avoue que je suis vraiment confus par cette notion de stockage d'adresse..
    Bonjour

    Ton problème peut (à mon avis) se résumer en 2 phrases
    1) je m'en sors mal avec l'adresse d'un pointeur (l'adresse de ta liste chainée)
    2) le contexte d'état de mon programme est très lourd (plein de trucs à mémoriser donc plein de variables à passer d'une fonction à une autre)

    Pour le 1, je conseille d'habitude d'encapsuler la liste chainée dans une structure.
    Exemple: voici ce que fait généralement un débutant dans les listes chainées
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    typedef struct s_noeud {
        type data;
        struct s_noeud *next;
    } t_liste;
     
    int main() {
        t_liste *liste;
        init_liste(&liste);
    }
    Déjà on voit qu'il y a un peu d'incohérence (nommer "liste" ce qui n'est en fait qu'un simple noeud). Et pour définir la fonction init_liste(), il se retrouve un peu coincé parce que recevant l'adresse d'un pointeur, on arrive à un double étoile...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void init_liste(t_liste **pt) {
        (*pt)=NULL;
    }
    Alors ça marche bien sûr, mais c'est pas aisément manipulable.

    Maintenant, regardons ce qui se passe si on encapsule la liste dans une structure dédiée à sa manipulation
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    typedef struct s_noeud {
        type data;
        struct s_noeud *next;
    } t_noeud;
     
    typedef struct {
        t_noeud *first;
    } t_liste;
     
    int main() {
        t_liste liste;
        init_liste(&liste);
    }

    Là on se retrouve avec juste un simple pointeur plus simple d'accès...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void init_liste(t_liste *l) {
        l->first=NULL;
    }

    Autre avantage: si demain on veut modifier la liste (rajouter par exemple un compteur ou autre), on le rajoute simplement dans la structure de liste et c'est tout. Les fonctions recevant la liste y auront immédiatement accès.
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    typedef struct {
        t_noeud *first;
        size_t nb;
    } t_liste;
     
    int main() {
        t_liste liste;
        init_liste(&liste);
    }
     
    void init_liste(t_liste *l) {
        l->first=NULL;
        l->nb=0;
    }

    Pour le point 2 c'est un peu la même chose. Au lieu de commencer à vouloir gérer séparément 1) ta bdd 2) tes erreurs 3) le log 4) ton écran et ensuite devoir passer 150 paramètres à toutes tes fonctions, ben tu crées une structure de contexte qui reçoit tout ce que tu as à gérer
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    typedef struct {
        t_liste bdd;
        t_liste error;
        FILE *log;
        FILE *screen;
    } t_contexte;
     
    int main() {
        t_contexte contexte;
        init_contexte(&contexte);
        ...
    }
     
    void init_contexte(t_contexte *c) {
        init_liste(&c->bdd);
        init_liste(&c->error);
        c->log=NULL;
        c->screen=NULL;
    }

    Bref tu encapsules ensemble les trucs qui vont ensembles, ce qui préfigure un peu l'objet...
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2013
    Messages : 45
    Points : 25
    Points
    25

    Par défaut

    Merci a vous deux pour vos explications.
    Je comprend beaucoup mieux certain concept.

    Par contre, ca je ne comprend pas

    Citation Envoyé par Matt_Houston Voir le message
    Pour garder trace du contexte (l'état de ton système), tu as deux solutions :

    • fournir des fonctions de création et de destruction de contexte et passer les objets initialisés par la bibliothèque (possiblement opaques) à chaque appel de traitement.


    En plus d'avantages en termes de lisibilité et de sécurité, la seconde solution rend ta bibliothèque ré-entrante : les appels ne modifient pas l'état global et peuvent être enchaînés dans n'importe quel ordre, depuis n'importe quel thread, pour peu qu'ils opèrent sur des contextes différents.
    qui a m'ont avis, répond en partie à ma question dans ce topic peut etre?? https://www.developpez.net/forums/d1...ic-modele-mvc/






    J'avais déclarer une cellule de cette façon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    struct cellRoot
    {
    	CELL	*usrFirstCell;
    	CELL	*usrLastCell;
     
    	CELL	*ctFirstCell;
    	CELL	*ctLastCell;
     
    	CELL	*msgFirstCell;
    	CELL	*msgLastCell;
     
    };
    qui me servait a retrouver les cellules (node) de ma liste (sachant que CELL *ctFirstCell; CELL *ctLastCell; CELL *msgFirstCell; CELL *msgLastCell; sont remis à jours constamment en fonction de l'user.

    La cellule de "base"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
     
    typedef enum keyCell
    {
    	KEY_USER,
    	KEY_CONTACT,
    	KEY_MSG
    }
    KEYCELL;
     
    struct cell
    {
    	KEYCELL	keyCellId;
    	int		idCell;
    	void	*pData;
     
    	struct	cell *previousCell;
    	struct	cell *nextCell;
    };
    *pData ici me sert à y mettre les structures contenant indifféremment

    les user
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    struct listUsr
    {
    	int		dUserID;
    	char	*sUserName;
    	char	*sCreateTimeUsr;
    	int		dNbrContact;
    	int		dNbrTotalMsgUnread;
    	bool	isCurrentUsr;
     
    	CELL	*ctFirstCell;
    	CELL	*ctLastCell;
    };
    les contacts
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    struct listContact
    {
    	int		dContactID;
    	char	*sContactName;
    	char	*sCreateTimeCt;
    	int		dNbrMsgCt;
    	int		dNbrMsgUnread;
     
    	CELL	*msgFirstCell;
    	CELL	*msgLastCell;
    };
    les messages
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    struct listMsg
    {
    	int		dMsgID;
    	char	*tMsg;
    	char	*sCreateTimeMsg;
    	bool	isRead;
    	bool	isSend;
    	char	*sSenderName;
    	int		dSenderId;
    };
    Du coup je me rend compte que je dois pousser cette idée un peu plus loin et faire une structure qui reprend tous les pointeurs dont j'aurai besoin de garde en mémoire.
    Juste un petite précision par rapport a cette structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    typedef struct {
        t_liste bdd;
        t_liste error;
        FILE *log;
        FILE *screen;
    } t_contexte;
    je dois la déclarer comme ? Globale (extérieur a mes fonctions) dans l'entête d'un de mes fichiers .c ? ou 'static' dans une de mes fonctions (cf https://c.developpez.com/cours/poly-...=page_1#LI-E-5 )
    Pq un a moment je dois rendre la main au 'main.c' et je ne veux pas lui donner cette structure a stocker et à me renvoyer à chaque appel de fonction. (??)

    Ce que je comptais faire, suite a vos suggestions, c'est de :
    - passer par un .c (api.c ?) qui intercepte les appels de fonctions que j'ai donné au main.c
    - déclarer un pointeur générique (void*) en static? global? qui contiendra la structure t_contexte (api.c n'a pas accès a la structure)
    - lancer l'initialisation de toutes les modules (bdd, gestion d'erreurs, ...) dans lesquelles j'ai des allocations dynamique (liste) ou des pointeurs (sur fichiers par ex) que je veux garder en leur passant le pointeur générique
    - chaque module fait sa cuisine et met dans la structure les pointeurs dont il aura besoin plus tard pour bosser (chaque module aura accès à la définition de la structure via un fichier .h)
    - rendre le pointeur de cette structure a l'api.c toujours sous forme de pointeurs générique et qui sera contenu dans un variable de type (globale?? static?) pour la rendre permanente en mémoire
    - mettre un flag a 1 pour signaler qu'une première initialisation des modules ont déjà été effectué avec succès et que l'on ne doit plus le faire
    - passer le pointeur de cette structure a mon controller.c a chaque fois que l'api fait le relais entre le main.c et le controller.c

    (désolé si ca n'est pas écrit de façon plus claire et peut être pas avec les bons termes )
    ??


    Si j'ai bon (??), il ne me reste plus qu'a comprendre ce topic https://www.developpez.net/forums/d1...ic-modele-mvc/

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    5 928
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 5 928
    Points : 16 386
    Points
    16 386
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par Dunkhan Voir le message
    Juste un petite précision par rapport a cette structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    typedef struct {
        t_liste bdd;
        t_liste error;
        FILE *log;
        FILE *screen;
    } t_contexte;
    je dois la déclarer comme ? Globale (extérieur a mes fonctions) dans l'entête d'un de mes fichiers .c ? ou 'static' dans une de mes fonctions (cf https://c.developpez.com/cours/poly-...=page_1#LI-E-5 )
    Dans mon exemple je l'ai mise dans le main. Ensuite, je la passe à qui en a besoin (donc à priori tout le monde). Ok, en général j'aime pas les globales mais bon, peut-être que là, une globale peut s'envisager.
    Donc dans le source contenant le main...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    t_contexte contexte;
    int main() {
        extern t_contexte contexte;    // Faculatif mais plus propre
        init_contexte();
        ...
    }
     
    void init_contexte() {
        extern t_contexte contexte;    // Faculatif mais plus propre
        init_liste(&contexte.bdd);
        init_liste(&contexte.error);
        contexte.log=NULL;
        contexte.screen=NULL;

    Ensuite, dans tous les autres sources contenant une fonction qui a besoin d'accéder au contexte...

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    extern t_contexte contexte;
     
    fonction_truc() {
        extern t_contexte contexte;    // Faculatif mais plus propre
        contexte.log...;
    }

    Citation Envoyé par Dunkhan Voir le message
    - déclarer un pointeur générique (void*) en static? global? qui contiendra la structure t_contexte (api.c n'a pas accès a la structure)
    Pourquoi un pointeur pour stocker une seule instance de contexte ??? Ca va t'obliger à un malloc(1 * sizeof(t_contexte)) ce qui est très con puis un free()...
    Dans mon exemple j'ai déclaré une variable de ce type et non un pointeur...
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2013
    Messages : 45
    Points : 25
    Points
    25

    Par défaut

    Je pense que j'ai compris l'essentiel.

    J'ai aussi trouver les réponses sur les constructeur/destructeur dans les tutos http://emmanuel-delahaye.developpez....nnees-c/#LIV-A

    Et de fait, je comprend mieux la différence entre déclarer une variable dynamique/non-dynamique. J'en étais arrivé à la même conclusion en concevant le design de mon prg, il me fallait une structure non dynamique pour stocker les premiers états d'initialisation des modules.
    Par contre, je vais déclarer la structure "t_contexte" dans le core, puisque c'est lui qui contiendra mes "bibliothèques" perso de gestion d'erreurs, d'allocation de mémoires, ...

    Merci pour vos réponses

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MCD] Application de gestion des projets
    Par anahoona dans le forum Schéma
    Réponses: 1
    Dernier message: 31/07/2012, 10h52
  2. [MS-DOS] Application de gestion des stocks
    Par ¤dinky¤ dans le forum Scripts/Batch
    Réponses: 4
    Dernier message: 30/01/2006, 15h25
  3. Application de gestion des sms sur PC
    Par andyvo dans le forum Langage
    Réponses: 9
    Dernier message: 21/10/2005, 00h49
  4. Application international (Gestion des dates)
    Par vsavoir dans le forum C++Builder
    Réponses: 2
    Dernier message: 01/08/2005, 11h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo