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 :

tableau de pointeur dynamique


Sujet :

C

  1. #1
    Membre habitué
    Homme Profil pro
    En rupture avec la societé
    Inscrit en
    Novembre 2008
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : En rupture avec la societé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 144
    Points : 194
    Points
    194
    Par défaut tableau de pointeur dynamique
    bonjour,

    avec ma petite connaissance actuelle du c, je cherche a alloué un tableau de pointeurs de type struct Contact.

    dans mes divers tests je passe donc un paramètre **pContact dans une fonction pour effectué mon allocation mais a la sortie de la fonction le tableau de pointeur de type struct reste null.

    Contact est une structure qui possède une autre structure adresse
    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
     
    typedef struct Adresse Adresse;
    struct Adresse {
    	int numero;
    	char rue[128];
    	char codePostal[8];
    	char ville[50];
    	char pays[50];
    };
     
    typedef struct Contact Contact;
    struct Contact{
    	char nom[50];
    	char prenom[50];
    	int age;
    	Adresse adresse;
    };
    la fonction qui me pose problème
    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
    28
     
    void allocContacts(Contact **pContact, int taille){
     
    	static int oldTaille = 0;
    	int tailleTotal = oldTaille + taille;
     
    	if(oldTaille == 0){		
     
    		pContact = malloc(taille * sizeof(pContact));
     
    	}else{
     
    		pContact = realloc(pContact, (tailleTotal * sizeof(pContact)));
    	}
     
    	if(pContact == NULL){
    		printf("Erreur allocation !");
    		exit(EXIT_FAILURE);
    	}
     
    	for(int i=0; i < tailleTotal; i++){
    			if (pContact[i] == NULL) {
    				pContact[i] = malloc(sizeof(*(pContact[i])));
    			}
    	}
     
    	oldTaille += taille;
    }
    le test de la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Contact **pContact = NULL;
    	allocContacts(pContact, 2);
     
    	allocContacts(pContact, 5);
    je pense que mon allocation pour un élément du tableau est fausse.
    petit détail, je suis sur mac os x
    Merci pour vos lumières

  2. #2
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Bonjour,

    je ne connais pas l'énoncé de ton exercice, donc il se peut que je trompe dans le développement ci-dessous.

    Tu as un double pointeur mais j'ai bien l'impression que ce que tu essayes de faire n'en nécessite pas. Corrige moi si je me trompe, mais dans ton esprit, est-ce que tu alloues N cases mémoires sensée contenir l'adresse des structures ? N'oublie pas que tu accèdes à un double pointeur comme pour un tableau à 2 dimensions donc : t[][].

    Je vais continuer comme si un tableau à deux dimensions était inutile. Tout d'abord ce qui serait plus propre et plus pratique, ça serait de définir une structure Carnet, ensuite tu peux plus aisément utiliser et manipuler les contacts.

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    #include <string.h>
     
    struct Adresse {
    	int numero;
    	char rue[128];
    	char codePostal[8];
    	char ville[50];
    	char pays[50];
    };
     
    typedef struct Contact Contact;
    struct Contact{
    	char nom[50];
    	char prenom[50];
    	int age;
    	Adresse adresse;
    };
     
    typedef struct // Déclaration plus courte.
    {
      int taille_reserve ;
      int taille_reelle ;
      Contact* tous ;
    } Carnet ;
     
     
    void init ( Carnet* carnet )
    {
      carnet->taille_reserve = 0 ;
      carnet->taille_reelle = 0 ;
      carnet->tous = NULL ;
    }
     
    void extend_memory ( Carnet* pCarnet , int new_size )
    {
    	if(pCarnet->tous == NULL){		
     
    		pCarnet->tous = (Contact*) malloc(new_size * sizeof(Contact));
     
    	}else{
    		pCarnet->tous = (Contact*) realloc(pCarnet->tous, ((new_size + pCarnet->taille_reserve) * sizeof(Contact)));
    	}
     
    	if(pCarnet->tous == NULL){
    		printf("Erreur allocation !");
    		exit(EXIT_FAILURE);
    	}
           pCarnet->taille_reserve += new_size ;
    }
     
    void ajouter_contact ( Carnet* pCarnet , const char* nom )
    {
      // Verification qu'il reste assez de place, sinon soit code d'erreur ou reallocation tacite. Non fait ici..
     
       strncpy( pCarnet->tous[pCarnet->taille_reelle].nom , nom, 50) ;
       ++(pCarnet->taille_reelle) ;
    }
     
    int main()
    {
      Carnet carnet ;
     
      init( &carnet );
      extend_memory( &carnet, 1 );
     
      ajouter_contact( &carnet, "Gertrude" );
     
      extend_memory( &carnet, 10 ) ;
     
      ajouter_contact( &carnet, "Jean" ) ;
     
      printf("%s\n",carnet.tous[0].nom );
      printf("%s\n", carnet.tous[1].nom );
     
      return 0;
    }
    Je l'ai testé et ça marche, il reste beaucoup de chose à améliorer évidemment, notamment au niveau de la gestion de la mémoire ! En temps normal, quand on ne connait pas la taille exacte et qu'elle peut souvent s'agrandir, et qu'on a pas besoin d'accéder aux cases mémoires directement (tableau[0]), on utilise le principe de liste chainée. L'avantage c'est que tu n'as pas a réserver des parties de mémoire inutilisées.

    Je pense que ça serait plus adapté à ton exercice, mais c'est ton choix.

    Bonne soirée.

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par burndev Voir le message
    bonjour,

    avec ma petite connaissance actuelle du c, je cherche a alloué un tableau de pointeurs de type struct Contact.

    dans mes divers tests je passe donc un paramètre **pContact dans une fonction pour effectué mon allocation mais a la sortie de la fonction le tableau de pointeur de type struct reste null.

    Contact est une structure qui possède une autre structure adresse
    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
     
    typedef struct Adresse Adresse;
    struct Adresse {
    	int numero;
    	char rue[128];
    	char codePostal[8];
    	char ville[50];
    	char pays[50];
    };
     
    typedef struct Contact Contact;
    struct Contact{
    	char nom[50];
    	char prenom[50];
    	int age;
    	Adresse adresse;
    };
    la fonction qui me pose problème
    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
    28
     
    void allocContacts(Contact **pContact, int taille){
     
    	static int oldTaille = 0;
    	int tailleTotal = oldTaille + taille;
     
    	if(oldTaille == 0){		
     
    		pContact = malloc(taille * sizeof(pContact));
     
    	}else{
     
    		pContact = realloc(pContact, (tailleTotal * sizeof(pContact)));
    	}
     
    	if(pContact == NULL){
    		printf("Erreur allocation !");
    		exit(EXIT_FAILURE);
    	}
     
    	for(int i=0; i < tailleTotal; i++){
    			if (pContact[i] == NULL) {
    				pContact[i] = malloc(sizeof(*(pContact[i])));
    			}
    	}
     
    	oldTaille += taille;
    }
    le test de la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Contact **pContact = NULL;
    	allocContacts(pContact, 2);
     
    	allocContacts(pContact, 5);
    je pense que mon allocation pour un élément du tableau est fausse.
    petit détail, je suis sur mac os x
    Merci pour vos lumières
    Salut
    Tu as un gros problème de conception car tu cherches à faire une fonction qui modifier qqchose qu'on lui passe en paramètre. Mais tu as dû apprendre que pour ça, la fonction doit recevoir l'adresse de cette chose ; adresse qu'elle stocke dans un <truc> *pt et ensuite elle doit travailler sur *pt.
    Donc si tu veux faire une fonction qui modifie un "contact **", alors elle doit recevoir l'adresse de ce "contact **" qu'elle stockera dans un "contact *** pt". Et ensuite toutes tes opérations devront se faire sur *pt chaque fois que tu voudras modifier le contact **.

    De plus, le test pContact[i] == NULL est mauvais car ce n'est pas parce que tu as alloué une zone que son contenu est forcément à NULL !!! Donc pContact est alloué, oui, mais pContact[i] n'est pas à NULL donc ce test inutile empêche l'allocation de pContatc[i].

    Maintenant, les détails
    1) il est plus courant de nommer ses structures s_qqchose et ses types t_qqchose. Ca évite de confondre avec des variables.
    2) tu fais malloc pour une première allocation et realloc aux allocations suivantes mais realloc est capable de s'adapter. Car si le pointeur qu'on lui passe est à null, realloc se comporte alors comme un malloc
    3) on ne sort jamais d'une fonction par exit. Si on veut quitter en erreur, on quitte alors via return et on laisse l'appelant gérer l'erreur. Imagine que le programmeur de malloc ait fait pareil que toi, tu serais bien embêté pour détecter un pb d'allocation. Donc fais la même chose et pense à ceux qui vont utiliser ta fonction (même si là c'est juste pour toi, c'est une habitude à prendre de suite car un jour tu pourrais programmer pour d'autres)
    4) le static est dangereux car ta fonction ne peut pas être appelée dans des contextes séparés

    Concernant ta fonction, tu peux la laisser comme elle est mais au lieu de la mettre void tu la mets de type Contact ** et tu lui fais renvoyer pContact. Et dans le main, tu fais Contact **pContact=allocContacts(2)
    Citation Envoyé par Trademark Voir le message
    Bonjour,

    je ne connais pas l'énoncé de ton exercice, donc il se peut que je trompe dans le développement ci-dessous.

    Tu as un double pointeur mais j'ai bien l'impression que ce que tu essayes de faire n'en nécessite pas.
    Ben si. Il essaye de gérer un ensemble d'éléments, chaque élément étant une structure allouée. Il faut donc un double pointeur (tout comme un ensemble de chaines nécessite aussi un double pointeur). Ou alors on déporte un des deux pointeurs dans une structure comme tu l'as fait.

    Citation Envoyé par Trademark Voir le message
    Je vais continuer comme si un tableau à deux dimensions était inutile. Tout d'abord ce qui serait plus propre et plus pratique, ça serait de définir une structure Carnet, ensuite tu peux plus aisément utiliser et manipuler les contacts.

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    #include <string.h>
     
    struct Adresse {
    	int numero;
    	char rue[128];
    	char codePostal[8];
    	char ville[50];
    	char pays[50];
    };
     
    typedef struct Contact Contact;
    struct Contact{
    	char nom[50];
    	char prenom[50];
    	int age;
    	Adresse adresse;
    };
     
    typedef struct // Déclaration plus courte.
    {
      int taille_reserve ;
      int taille_reelle ;
      Contact* tous ;
    } Carnet ;
     
     
    void init ( Carnet* carnet )
    {
      carnet->taille_reserve = 0 ;
      carnet->taille_reelle = 0 ;
      carnet->tous = NULL ;
    }
     
    void extend_memory ( Carnet* pCarnet , int new_size )
    {
    	if(pCarnet->tous == NULL){		
     
    		pCarnet->tous = (Contact*) malloc(new_size * sizeof(Contact));
     
    	}else{
    		pCarnet->tous = (Contact*) realloc(pCarnet->tous, ((new_size + pCarnet->taille_reserve) * sizeof(Contact)));
    	}
     
    	if(pCarnet->tous == NULL){
    		printf("Erreur allocation !");
    		exit(EXIT_FAILURE);
    	}
           pCarnet->taille_reserve += new_size ;
    }
     
    void ajouter_contact ( Carnet* pCarnet , const char* nom )
    {
      // Verification qu'il reste assez de place, sinon soit code d'erreur ou reallocation tacite. Non fait ici..
     
       strncpy( pCarnet->tous[pCarnet->taille_reelle].nom , nom, 50) ;
       ++(pCarnet->taille_reelle) ;
    }
     
    int main()
    {
      Carnet carnet ;
     
      init( &carnet );
      extend_memory( &carnet, 1 );
     
      ajouter_contact( &carnet, "Gertrude" );
     
      extend_memory( &carnet, 10 ) ;
     
      ajouter_contact( &carnet, "Jean" ) ;
     
      printf("%s\n",carnet.tous[0].nom );
      printf("%s\n", carnet.tous[1].nom );
     
      return 0;
    }
    Effectivement c'est plus propre et plus dans l'optique poo (surtout le "taille_reservee" et "taille_relle" qui optimise le realloc et qui évite de devoir mémoriser la taille dans un static). Mais s'il s'agit d'un exercice comme tu l'as mentionné ça devient HS (trop pro quoi)
    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
    En rupture avec la societé
    Inscrit en
    Novembre 2008
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : En rupture avec la societé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 144
    Points : 194
    Points
    194
    Par défaut
    bonjour,

    après recherches et questions posées sur d'autre forum, je ne pensais etre dans l'obligation de déclarer un pointeur de tableau de pointeur de type struct. uniquement pour le retour du paramètre passé.

    pour ma part la solution est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void addContact(Contact ***pContact, int taille);
     
    Contact  **pContact = NULL;
    addContact(&pContact, 2);
    ou effectivement conservé ma fonction avec un retour du type.

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par burndev Voir le message
    bonjour,

    après recherches et questions posées sur d'autre forum, je ne pensais etre dans l'obligation de déclarer un pointeur de tableau de pointeur de type struct. uniquement pour le retour du paramètre passé.

    pour ma part la solution est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void addContact(Contact ***pContact, int taille);
     
    Contact  **pContact = NULL;
    addContact(&pContact, 2);
    ou effectivement conservé ma fonction avec un retour du type.

    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
    20
    21
    22
    23
    24
    25
    Contact **allocContacts(int taille){
     
    	Contact **pContact=NULL; 
    	static int newTaille = 0;
    	newTaille += taille;
     
     
    	pContact = realloc(pContact, newTaille * sizeof(*pContact));
    	if(pContact == NULL){
    		return NULL;
    	}
     
    	for(int i=newTaille - taille; i < newTaille; i++){
    		pContact[i] = malloc(sizeof(**pContact));
    	}
    	return pContact;
    }
     
    int main()
    {
    	Contact **pContact;
    	pContact=allocContacts(2);
     
    	pContact=allocContacts(5);
    }
    Pas parfait parfait (surtout si le realloc échoue alors que le malloc initial a réussi => perte du pointeur initialement alloué) mais c'est pour donner une idée...
    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]

Discussions similaires

  1. Allocation dynamique d'un tableau de pointeur
    Par Général03 dans le forum Débuter
    Réponses: 20
    Dernier message: 09/12/2009, 18h21
  2. Allocation dynamique: Tableau de pointeur sur char
    Par Anonymouse dans le forum Débuter
    Réponses: 4
    Dernier message: 21/10/2007, 10h57
  3. allocation dynamique d'un tableau de pointeurs
    Par Dilettante dans le forum C++
    Réponses: 9
    Dernier message: 29/06/2007, 23h41
  4. Réponses: 67
    Dernier message: 13/02/2007, 18h08
  5. Réponses: 13
    Dernier message: 01/10/2006, 00h25

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