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 structures avec des tableaux dynamiques


Sujet :

C

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2009
    Messages : 46
    Par défaut tableau de structures avec des tableaux dynamiques
    Bonjour,
    pour me faire la main en C, me suis posé un petit exo en relation avec le projet que j'ai en tête.
    Je définis une population comme un ensemble de familles, et je définis une famille par deux valeurs "le nombre d'enfants, et leurs âges", sachant qu'il peut ne pas avoir d'enfants.

    Ai donc écrit ce code (en faisant appel à la librairie GSL pour les nombres aléatoires).
    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
    #include <gsl/gsl_rng.h>
    #include <gsl/gsl_randist.h>
    #include <gsl/gsl_statistics.h>
    //      compilation: gcc *.c -L/usr/local/lib  -lgsl -lgslcblas -lm
    //      pour creer une population de 10 familles avec un nombre maximum de 5 enfants: ./a.out 10 5 123
    //      123 c'est pour le générateur de nombres aléatoires
     
    typedef struct Famille Famille;
    struct Famille{
    	int nEnfant;
    	int* ageEnfant;
    };
     
    void initializePopulation(gsl_rng *r, Famille* population, int nFamille, unsigned long int nMaxEnfant, int enfantParFamille[]);
     
    int main(int argc, char *argv[]){
    	// Recupere les parametres depuis la ligne de commande
    	const int nFamille = atoi(argv[1]);	// nombre de familles
    	const unsigned long int nMaxEnfant = atoi(argv[2]);	// nombre d'enfants maximum
    	const int seed = atoi(argv[3]);	// graine pour le generateur de nombres aleatoires
     
    	int i = 0;
    	int j = 0;
    	int* enfantParFamille;	// tableau qui contiendra le nombre d'enfants par familles
    	enfantParFamille = malloc(nFamille * sizeof(int));
     
    	// Configure le generateur de nombres aleatoires
    	const gsl_rng_type *T;
    	gsl_rng *r;
    	gsl_rng_env_setup();
     
    	T=gsl_rng_default;
    	r=gsl_rng_alloc(T);
    	gsl_rng_set(r, seed);
     
    	// Initialiser la population
    	Famille population[nFamille];	// Je défini ici une population de N familles, mais toutes les familles n'ont pas la même taille...
    	initializePopulation(r, population, nFamille, nMaxEnfant, enfantParFamille);
     
    	// afficher les contenus
    	for(i=0; i<nFamille; i++){
    		printf("La famille %d a %d enfants.\n", i+1, enfantParFamille[i]);
    		if(enfantParFamille[i] > 0){
    			for(j=0; j<enfantParFamille[i]; j++){
    				printf("\tL'enfant %d de la famille %d a %d ans.\n", j+1, i+1, population[i].ageEnfant[j]);
    			}
    		}
    	}
    	free(population);
     
    	return(0);
    }
     
    // fonction qui génère n familles, avec chacune un nombre aléatoire d'enfants, eux mêmes avec des ages aléatoires
    void initializePopulation(gsl_rng *r, Famille* population, int nFamille, unsigned long int nMaxEnfant, int enfantParFamille[]){
    	int i = 0;
    	int j = 0;
    	const unsigned long int ageMax = 100;
     
    	for(i=0; i<nFamille; i++){	// boucle le long des familles
    		enfantParFamille[i] = gsl_rng_uniform_int(r, nMaxEnfant);	// la famille 'i' a entre 0 et (nMaxEnfant-1) enfants
    		if(enfantParFamille[i] == 0){	// si la famille 'i' a zéro enfant, je lui attribue un age de '-9' ans (ma façon de gérer les NA)
    			population[i].ageEnfant = malloc(1 * sizeof(int));
    			*population[i].ageEnfant = -9;
    		}else{
    			population[i].ageEnfant = malloc(enfantParFamille[i] * sizeof(int));// si la famille 'i' a plus que 0 enfant, je leur attribue des ages aléatoires
    			for(j=0; j<enfantParFamille[i]; j++){	// boucle le long des enfants
    				population[i].ageEnfant[j] = gsl_rng_uniform_int(r, ageMax) + 1;
    			}
    		}
    	}
    }
    Le code compile chez moi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ~/Documents/C/test$ gcc *.c -L/usr/local/lib  -lgsl -lgslcblas -lm
    ~/Documents/C/test$
    Mais en revanche il ne fonctionne pas bien:
    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
    ~/Documents/C/test$ ./a.out 10 5 123
    La famille 1 a 3 enfants.
    	L'enfant 1 de la famille 1 a 72 ans.
    	L'enfant 2 de la famille 1 a 29 ans.
    	L'enfant 3 de la famille 1 a 43 ans.
    La famille 2 a 1 enfants.
    	L'enfant 1 de la famille 2 a 70 ans.
    La famille 3 a 2 enfants.
    	L'enfant 1 de la famille 3 a 72 ans.
    	L'enfant 2 de la famille 3 a 72 ans.
    La famille 4 a 2 enfants.
    	L'enfant 1 de la famille 4 a 43 ans.
    	L'enfant 2 de la famille 4 a 79 ans.
    La famille 5 a 4 enfants.
    	L'enfant 1 de la famille 5 a 42 ans.
    	L'enfant 2 de la famille 5 a 69 ans.
    	L'enfant 3 de la famille 5 a 58 ans.
    	L'enfant 4 de la famille 5 a 49 ans.
    La famille 6 a 0 enfants.
    La famille 7 a 1 enfants.
    	L'enfant 1 de la famille 7 a 41 ans.
    La famille 8 a 1 enfants.
    	L'enfant 1 de la famille 8 a 63 ans.
    La famille 9 a 3 enfants.
    	L'enfant 1 de la famille 9 a 33 ans.
    	L'enfant 2 de la famille 9 a 44 ans.
    	L'enfant 3 de la famille 9 a 25 ans.
    La famille 10 a 0 enfants.
    Erreur de segmentation (core dumped)
    Malgré les tutos que je lis sur le net, il y a une chose que je ne sais pas encore faire, c'est d'allouer (et libérer) de la mémoire pour un tableau (population) de structures (ici, la structure Famille) contenant elles mêmes des tableaux (ageEnfant) de tailles variables.

    Je me demandais si c'était possible de faire ça ?

    A bientôt,
    M.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Étant donné le champ nEnfant de la structure, pourquoi ne pas l'utiliser à la place de enfantParFamille ?

    Pour la gestion des familles sans enfants, j'aurais plus tendance à fixer le pointeur à NULL.

    Sinon en ce qui concerne la gestion de mémoire, la règle est simple :
    À chaque malloc() doit correspondre un free().
    Dans ton code, Famille population[nFamille]; utilise un VLA (Variable-Length Array) qui gère lui-même sa mémoire pas de free() dessus (c'est ce qui provoque ton erreur de segmentation).
    Par contre, tu alloues chaque champ ageEnfant de cette population, il te faut donc parcourir ce tableau et faire un free() sur chaque population[i].ageEnfant ainsi que enfantParFamille.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2009
    Messages : 46
    Par défaut
    il te faut donc parcourir ce tableau et faire un free()
    C'est génial! Ça marche, merci! Ai modifié le code du coup en ajoutant la fonction libererMemoirePopulation() et qui fait ce que tu dis. Je n'y avais pas pensé.
    Honnêtement, tout ne me parait pas super clair pour le moment.
    Par exemple, je n'arrive pas bien à comprendre comment fonctionne l'OS pour allouer la mémoire à mon tableau population sans connaitre la taille des éléments qui composent la population puisque ces tailles sont définies après. Je m'attendais à ce que ça plante en tentant ces lignes et suis finalement le premier surpris à voir que ça marche.

    En revanche, je ne comprends pas bien pourquoi ça plante si je mets un trop grand nombre de familles dans ma population.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ~/Documents/C/test$ ./a.out 50000 3 123 >/dev/null 
    ~/Documents/C/test$ ./a.out 5000000 3 123 >/dev/null 
    Erreur de segmentation (core dumped)
    P.S. mise à jour du code:
    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
    78
    79
    80
    81
    82
    83
    #include <gsl/gsl_rng.h>
    #include <gsl/gsl_randist.h>
    #include <gsl/gsl_statistics.h>
    //      gcc *.c -L/usr/local/lib  -lgsl -lgslcblas -lm
    //      ./a.out 10 5 123
     
    typedef struct Famille Famille;
    struct Famille{
    	int nEnfant;
    	int* ageEnfant;
    };
     
    // Prototypes
    void initializePopulation(gsl_rng *r, Famille* population, int nFamille, unsigned long int nMaxEnfant, int enfantParFamille[]);
    void libererMemoirePopulation(Famille* population, int nFamille);
     
    // Main
    int main(int argc, char *argv[]){
    	// Recupere les parametres depuis la ligne de commande
    	const int nFamille = atoi(argv[1]);	// nombre de familles
    	const unsigned long int nMaxEnfant = atoi(argv[2]);	// nombre d'enfants maximum
    	const int seed = atoi(argv[3]);	// graine pour le generateur de nombres aleatoires
     
    	int i = 0;
    	int j = 0;
    	int* enfantParFamille;	// tableau qui contiendra le nombre d'enfants par familles
    	enfantParFamille = malloc(nFamille * sizeof(int));
     
    	// Configure le generateur de nombres aleatoires
    	const gsl_rng_type *T;
    	gsl_rng *r;
    	gsl_rng_env_setup();
     
    	T=gsl_rng_default;
    	r=gsl_rng_alloc(T);
    	gsl_rng_set(r, seed);
     
    	// Initialiser la population
    	Famille population[nFamille];	// Je défini ici une population de N familles, mais toutes les familles n'ont pas la même taille...
    	initializePopulation(r, population, nFamille, nMaxEnfant, enfantParFamille);
     
    	// afficher les contenus
    	for(i=0; i<nFamille; i++){
    		printf("La famille %d a %d enfants.\n", i+1, enfantParFamille[i]);
    		if(enfantParFamille[i] > 0){
    			for(j=0; j<enfantParFamille[i]; j++){
    				printf("\tL'enfant %d de la famille %d a %d ans.\n", j+1, i+1, population[i].ageEnfant[j]);
    			}
    		}
    	}
     
    	//libere la memoire
    	libererMemoirePopulation(population, nFamille);
    	free(enfantParFamille);
    	return(0);
    }
     
    // fonction qui génère n familles, avec chacune un nombre aléatoire d'enfants, eux mêmes avec des ages aléatoires
    void initializePopulation(gsl_rng *r, Famille* population, int nFamille, unsigned long int nMaxEnfant, int enfantParFamille[]){
    	int i = 0;
    	int j = 0;
    	const unsigned long int ageMax = 100;
     
    	for(i=0; i<nFamille; i++){	// boucle le long des familles
    		enfantParFamille[i] = gsl_rng_uniform_int(r, nMaxEnfant);	// la famille 'i' a entre 0 et (nMaxEnfant-1) enfants
    		if(enfantParFamille[i] == 0){	// si la famille 'i' a zéro enfant, je lui attribue un age de '-9' ans (ma façon de gérer les NA)
    			population[i].ageEnfant = malloc(1 * sizeof(int));
    			*population[i].ageEnfant = -9;
    		}else{
    			population[i].ageEnfant = malloc(enfantParFamille[i] * sizeof(int));// si la famille 'i' a plus que 0 enfant, je leur attribue des ages aléatoires
    			for(j=0; j<enfantParFamille[i]; j++){	// boucle le long des enfants
    				population[i].ageEnfant[j] = gsl_rng_uniform_int(r, ageMax) + 1;
    			}
    		}
    	}
    }
     
    void libererMemoirePopulation(Famille* population, int nFamille){
    	int i = 0;
    	for(i=0; i<nFamille; i++){
    		free(population[i].ageEnfant);
    	}
    }

  4. #4
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    En utilisant un VLA, au lieu de l'allocation dynamique, tu as créé une variable locale population occupant une vaste zone mémoire allouée sur la pile. Or, la quantité mémoire disponible sur la pile est bien moindre que celle disponible sur le tas.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2009
    Messages : 46
    Par défaut
    En utilisant un VLA, au lieu de l'allocation dynamique, tu as créé une variable locale population occupant une vaste zone mémoire allouée sur la pile. Or, la quantité mémoire disponible sur la pile est bien moindre que celle disponible sur le tas.
    Alors, pour tenter de résoudre ça, j'ai remplacé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	Famille population[nFamille];	// Je défini ici une population de N familles, mais toutes les familles n'ont pas la même taille...
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            Famille* population = NULL;     // Je défini ici une population de N familles, mais toutes les familles n'ont pas la même taille...
            population = malloc(nFamille * sizeof(Famille));
    Et plus aucun problème apparent !
    Merci encore !

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

Discussions similaires

  1. [XL-2010] MAJ Macro tableau onglet principal avec les tableaux secondaires des autres onglets
    Par Tesla.B dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 04/05/2015, 10h47
  2. [XL-2003] Instabilité des classeurs avec des Tableaux Croisés Dynamiques
    Par oohcalme dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 04/08/2009, 11h45
  3. Un tableau avec des colonnes dynamiques
    Par Cronycs dans le forum Struts 1
    Réponses: 5
    Dernier message: 07/06/2007, 13h38
  4. Réponses: 6
    Dernier message: 20/02/2007, 17h00
  5. Réponses: 8
    Dernier message: 09/03/2006, 17h48

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