IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Problème tableau de structures


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    BTS SIO
    Inscrit en
    Janvier 2016
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ardennes (Champagne Ardenne)

    Informations professionnelles :
    Activité : BTS SIO
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2016
    Messages : 8
    Par défaut Problème tableau de structures
    Bonsoir à tous,
    Je créé ce sujet car je suis bloqué sur une fonction que je dois réaliser et je n'arrive vraiment pas à y parvenir malgré tout mon acharnement, mes recherches... Je commence sérieusement à désespérer.

    Donc je dispose de la structure suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    /** table dynamique de personne */
    typedef struct {
        /**Le nombre de personne dans la table*/
        int recordCount;
        /**Les données des personnes. Tableau 2d de strings.
         * Note: records[Idpersonne][0] est le nom de la Idpersonne ème personne
         * Note: records[Idpersonne][1] est le mot de passe de la Idpersonne ème personne
         */
        char *** records;
    } PersonneTable;
    Donc déjà ce qui me gène énormément est ce fameux ***records.

    Mon cours explique ce q'est un pointeur mais ne rentre pas dans les détails.
    Je dois écrire une fonction qui permet d'insérer le nom d'une personne et son mot de passe si elle n'est pas déjà dans la liste ou qui modifie le mot de passe d'une personne déjà présent dans la liste.
    La fonction retourne la position de la personne dans la table.Le premier commence à 0.

    Voici la fonction que j'ai faite: (Les paramètres de la fonctions sont imposés)

    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
     
    int (PersonneTable_setPersonne)(PersonneTable * table, const char * name, const char * password) {
        if(PersonneTable_findPersonne(table, name) == -1)
        {
            table->records[table->recordCount][0] = dupliquer(name);/** C'est cette ligne qui ne fonctionne pas et que je n'arrive pas à résoudre. Idem la ligne du dessous.**/
            table->records[table->recordCount][1] = dupliquer(password);
            table->recordCount = table->recordCount + 1;
            return table->recordCount;
        }
        else //Pour l'instant ce code n'a jamais pu etre testé mais le problème est le même
        {
            table->records[PersonneTable_findPersonne(table, name)][1] = dupliquer(password);
            table->recordCount = table->recordCount +1;
            return PersonneTable_findPersonne(table, name);
        }
    }
    La fonction dupliquer(char * string) alloue sur le tas et retourne une copie de la chaine en paramètre.
    La fonction PersonneTable_findPersonne(table, name) retourne -1 si la personne n'a pas été trouvé, sinon son indice.
    Donc vu qu'au début table est vide on entre directement dans le if.

    Si quelqu'un pouvait m'aider ce serait vraiment super!

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    char*** records est a priori un pointeur de pointeur de pointeur sur un caractère.
    D'après l'énoncé, on souhaite un pointeur sur un tableau de tableaux de caractère, donc un pointeur sur un tableau de chaînes de caractères.
    L'allocation de chaînes est effectuée par dupliquer()
    L'allocation du tableau de 2 chaînes doit être effectuée.
    L'allocation du tableau des personnes doit aussi être effectuée.
    Faisons un dessin pour mieux y voir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
       char***          char(s)**          char(s)*           char(s)
      +--------+        +--------+        +--------+        +--+--+--+--+
      |record--+------->|      --+------->|  [0] --+------->|  |  |  |\0|          <== chaîne à allouer
      +--------+        +--------+        +--------+        +--+--+--+--+--+--+--+
                        |        |        |  [1] --+------->|  |  |  |  |  |  |\0| <== chaîne à allouer
                        +--------+        +--------+        +--+--+--+--+--+--+--+
                        |        |          \doit être alloué
                        +--------+
                             \doit être alloué et réalloué si le tableau grandi
    Il est préférable de créer une fonction ajouterRecord() qui allouera la place pour la nouvelle personne.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void ajoutRecord( PersonneTable* table , const char* name , const char* password ) {
       table->record = realloc( table->record , sizeof(char**) * (table->recordCount+1) ); // alloc 1 personne de plus
       table->record[table->recordCount] = malloc( sizeof(char*) * 2 ); // alloc les 2 acces name et password
       table->record[table->recordCount][0] = dupliquer(name); // initialise (et alloc) pour name
       table->record[table->recordCount][1] = dupliquer(password);
       table->recordCount++;
    }
    Et attention pour le else, avant de reallouer pour un nouveau password, il faut penser à libérer le password précédent!

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 830
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par arccho Voir le message
    Donc je dispose de la structure suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    /** table dynamique de personne */
    typedef struct {
        /**Le nombre de personne dans la table*/
        int recordCount;
        /**Les données des personnes. Tableau 2d de strings.
         * Note: records[Idpersonne][0] est le nom de la Idpersonne ème personne
         * Note: records[Idpersonne][1] est le mot de passe de la Idpersonne ème personne
         */
        char *** records;
    } PersonneTable;
    Donc déjà ce qui me gène énormément est ce fameux ***records.
    Ben oui. Au delà de 2 étoiles, l'abstraction devient difficile.

    Pourquoi ne pas transformer ton tableau 3D (une liste de couples nom+mot de passe) en
    • une structure contenant un nom et un mot de passe
    • un tableau 1D d'éléments de cette structure
    ???
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    typedef struct {
    	char *nom;
    	char *passwd;
    } t_login;
     
    typedef struct {
    	size_t recordCount;
    	size_t sz_alloc;
    	// Je me sers de cette variable quand je fais de l'allocation dynamique par "blocs".
    	// Si par exemple j'alloue 1000, je stocke cette valeur puis je ne réalloue 1000 de plus que quand le "recordCount" atteint "sz_alloc"...
    	t_login *tabLogin;	// Un tableau dont chaque élément contiendra le nom et le mot de passe
    } t_tabPersonne;

    Ensuite te suffit d'écrire table.tabLogin[n].nom=dupliquer(name) et table.tabLogin[n].passwd=dupliquer(passwd). Et tu peux même te passer de "dupliquer()" (surtout que la fonction strdup() fait déjà ça) si tu présupposes une taille "suffisante" pour le nom et passwd...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    typedef struct {
    	char nom[100];
    	char passwd[100];
    } t_login;
     
    strcpy(table.tabLogin[n].nom, name);
    strcpy(table.tabLogin[n].passwd, passwd);


    Citation Envoyé par arccho Voir le message
    Mon cours explique ce qu'est un pointeur mais ne rentre pas dans les détails.
    Ben là ça va être ardu de travailler en triple indirection si tu ne maîtrise pas déjà la simple indirection !!!

    Citation Envoyé par arccho Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            table->records[table->recordCount][0] = dupliquer(name);/** C'est cette ligne qui ne fonctionne pas et que je n'arrive pas à résoudre. Idem la ligne du dessous.**/
    Là on va avoir un problème. Si table->recordCount contient le nombre réel d'éléments, alors c'est table->recordCount - 1 qu'il faut demander. Ben oui, un tableau qui contient 3 éléments aura ses indices allant de 0 à 2 !!!
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Membre habitué
    Homme Profil pro
    BTS SIO
    Inscrit en
    Janvier 2016
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ardennes (Champagne Ardenne)

    Informations professionnelles :
    Activité : BTS SIO
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2016
    Messages : 8
    Par défaut
    Super dalfab, merci beaucoup pour ton dessein et tes explications.
    Donc il fallait allouer pour que ça fonctionne.

    Mais malgré tout ça j'ai encore du mal.

    Voici le code de ma fonction qui à priori fonctionne:

    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
    20
    21
    22
    23
    24
    25
    26
    27
     
    int (SetPersonne)(PersonneTable * table, const char * name, const char * password) {
        if(FindPersonne(table, name) == -1)
        {
            table->records = realloc( table->records , sizeof(char**) * (long unsigned)(table->recordCount+1) );
            if(table->records == NULL)
            {
                exit(-1);
            }
            table->records[table->recordCount] = malloc( sizeof(char*) * 2 );
            if(table->records[table->recordCount] == NULL)
            {
                exit(-1);
            }
     
            table->records[table->recordCount][0] = duplicateString(name); /** pour cette ligne,  on fait pointer table->records[table->recordCount][0]  sur le tableau créé par duplicateString(name) c'est bien ca?**/
            table->records[table->recordCount][1] = duplicateString(password);
            table->recordCount = table->recordCount + 1;
            return table->recordCount -1;
        }
        else
        {
            free(table->records[FindPersonne(table, name)][1]); 
            table->records[FindPersonne(table, name)][1] = duplicateString(password);
            return FindPersonne(table, name);
        }
    }

    Sve@r j'aurais bien aimé pouvoir simplifier mais dans le cadre de mon projet, je n'ai pas le droit de modifier quoi que ce soit :/
    Pour cette partie de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     table->records[table->recordCount][0] = dupliquer(name);
    table a été initialisé et est pour l'instant vide. recordCount vaut 0
    Ca ne pose pas de soucis vu que j'incrémente sa valeur seulement à la fin de la fonction.

    A présent je me retrouve bloqué sur la dernière fonction à coder... Celle ci doit permettre de supprimer une personne à partir d'un index donné. Si sur 5 enregistrement (donc le dernier est le 4ème) je supprime le 2ème par exemple, il faut que le 3ème deviennent le 2ème et ainsi de suite.
    En utilisant ton dessin dalfab, j'ai voulu libérer le contenu name et password de la personne à supprimer et décaler chaque pointeur vers ce à quoi il pointe puis supprimer mon dernier enregistrement . Mais il y a quelque chose qui m'échappe, que je n'ai pas du bien comprendre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void (RemoveRecord)(PersonneTable * table, int recordIndex) {
        int i;
        free(table->records[recordIndex][0]); /**Je veux supprimer le contenu de name et password mais j'ai l'impression que ca fait autre chose**/
        free(table->records[recordIndex][1]);
     
        for(i = recordIndex; i < GetRecordCount(table)-1; i++)
        {
            table->records[i] = table->records[i+1]; /**Ici je décale chaque pointeur de 1 jusqu’à l'avant dernier en commençant à la personne à supprimer. D'après mes tests ça fonctionne bien
        }
        free(table->records[GetRecordCount(table)-1]); //Je souhaite supprime la dernière personne mais le code ne doit pas être bon
        table->recordCount =     table->recordCount -1;
    }
    Et bien évidemment ça ne fonctionne pas. Je pense que les problèmes viennent des free(). J'ai aussi essayé free(*(table->records[GetRecordCount(table)-1]));
    Au final, actuellement lorsque je veux supprimer un enregistrement avec ce code: si j'ai 5 enregistrements mon index max est censé passer de 4 à 3 mais lorsque je fais un printf du 4ème enregistrement ça m'affiche toujours quelque chose.

  5. #5
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    • Il faut en effet libérer les deux chaines avant la recopie,
    • Mais Il faut aussi libérer la table contenant indiquant ces deux chaines free( table->records[recordIndex] );.
    • Ensuite transférer les données au delà de l'indice à supprimer à un indice inférieur (si conserver l'ordre n'est pas important, on peut plus simplement ne recopier que le dernier sur l'indice qui disparaît.)
    • Il faut aussi décrémenter le nombre d'éléments que l'on considère être dans le tableau.
    • Il manque aussi redimensionner la table records sachant qu'elle a désormais une ligne de moins
      table->records = realloc( table->records , sizeof(char**) * table->recordCount );.
    Et là ne surtout pas essayer d'utiliser le dernier indice qui vient de disparaître, la mémoire peut ou pas contenir des restes de données disparues.

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

Discussions similaires

  1. Problème tableau de structures et pointeur
    Par sunshine25 dans le forum Débuter
    Réponses: 11
    Dernier message: 02/04/2016, 20h37
  2. problème tableau de structure
    Par alaninho dans le forum C
    Réponses: 9
    Dernier message: 24/08/2012, 14h18
  3. problème tableau de structure
    Par scary dans le forum Débuter
    Réponses: 8
    Dernier message: 30/03/2008, 19h38
  4. Problème avec un tableau de structure
    Par Sofute dans le forum C
    Réponses: 10
    Dernier message: 16/10/2007, 15h29
  5. Problème free() : Tableau de structures
    Par bit_o dans le forum C
    Réponses: 11
    Dernier message: 28/04/2007, 15h53

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