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 :

Allocation de mémoire et initialisation d'un tableau de structures par une fonction


Sujet :

C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2011
    Messages : 10
    Points : 9
    Points
    9
    Par défaut Allocation de mémoire et initialisation d'un tableau de structures par une fonction
    Bonjour,

    Après un cours élémentaire sur les structures et l'allocation de mémoire, j'en ai repris les éléments dans le fichier joints pour vérifier si j'avais bien compris. Ce programme compile mais l'exécution pose des problèmes.

    Mon but est d'allouer la mémoire nécessaire à un tableau de structures de taille variable, d'en initialiser les champs de chaque élément du tableau et de vérifier le résultat en imprimant le tableau après initialisation. C'est un cas d'école qui n'a rien d'ambitieux.

    J'ai réalisé cette tâche de deux façons différentes :
    1 - allocation de mémoire dans le main() + initialisation du tableau dans le main() + impression dans le main().
    Cette partie du programme s'exécute parfaitement.
    2 - allocation de mémoire dans une fonction + initialisation du tableau dans la même fonction + impression dans le main().
    Tout semble bien se passe dans la fonction où l'impression locale du tableau initialisé est correcte. Par contre, l'impression dans le main() ne fonctionne pas et le programme s'arrête.

    Je pense que cela provient d'une gestion inadaptée des pointeurs mais je n'arrive pas à trouver la solution.

    J'ai eu récemment un cours de base sur les pointeurs et je vois bien que je n'ai pas tout assimilé.

    Si vous voyez où j'ai fait une erreur de débutant, je vous remercie par avance de l'aide que vous pourrez m'apporter,

    Cordialement vôtre,

    getud78
    Fichiers attachés Fichiers attachés

  2. #2
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Peux-tu insérer le code du programme entre balises [code] ? Sa consultation en deviendra plus aisée pour tout un chacun.

  3. #3
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    La valeur du pointeur tab_pers_2 est transmise à la fonction créer_tab() qui met à jour sa copie qui s'appelle tab.
    Ensuite main() utilise tab_pers_2 qui n'a pas changée (donc qui vaut toujours NULL) et l'utiliser va planter.

    Une fonction ne peut pas modifier une données externe, transmettre l'adresse de tab_pers_2 est indispensable
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /*...*/
    void creer_tab( int dim , mapersonne** ptab ) {
    /*...*/
        mapersonne *tab = malloc( dim * sizeof(mapersonne) ); // tab est locale
       *ptab = tab; // on met à jour via pointeur la variable de l'appelant
    /*...*/
    }
     
    int main() {
    /*...*/
       creer_tab( nb_pers , &tab_pers_2 );
    /*...*/
    }
    Ou bien on fait l'inverse, c'est plus simple : la fonction créer_tab() calcule un tab, en retourne la valeur. Et cette valeur de retour est à copier dans tab_pers_2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*...*/
    mapersonne* creer_tab( int dim ) {
        mapersonne *tab;
    /*...*/
       return tab;
    }
     
    int main() {
    /*...*/
       tab_pers_2 = creer_tab( nb_pers );
    /*...*/
    }

  4. #4
    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 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par getud78 Voir le message
    Je pense que cela provient d'une gestion inadaptée des pointeurs mais je n'arrive pas à trouver la solution.

    J'ai eu récemment un cours de base sur les pointeurs et je vois bien que je n'ai pas tout assimilé.
    Bonjour

    Même réponse que dalfab mais exprimée de façon plus générale: tu as dû apprendre qu'une fonction qui doit modifier une variable ne peut le faire que si on lui passe l'adresse de cette variable. Tu as (j'espère) eu des exemple de scanf() où on écrit int i; scanf("%d", &i).

    Il se trouve que du côté de la fonction, cette adresse qu'elle reçoit elle doit d'abord la stocker. Et on ne peut stocker une adresse que dans un pointeur.
    De plus, le pointeur de stockage d'une adresse est alors du type de la variable à laquelle correspond cette adresse. Si par exemple je passe l'adresse d'un int, alors la fonction stockera cette adresse dans un "int étoile". Et si je passe l'adresse d'un double, alors la fonction stockera cette adresse dans un "double étoile". Bref quel que soit le type générique "ttt" de la variable initiale, son adresse est toujours un "ttt étoile" (on rajoute juste "étoile" derrière son type).

    De plus, dans la fonction elle-même, toute référence à la variable se fera par le "pointé de". Et en C, l'opération "pointer sur" se fait via l'opérateur étoile.

    Petit exemple: une fonction qui initialise un int et un double à 0
    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
    void init_int(int *x) {
    	(*x)=0; 			// Je mets des parenthèses pour bien montrer comment lire cette expression => 0 va dans la zone pointée par x
    }
     
    void init_double(double *x) {
    	(*x)=0; 			// Idem
    }
     
    int main() {
    	int i=5;
    	double dbl=10;
    	init_int(&i);
    	init_double(&dbl);
    	printf("i=%d, dbl=%lf\n", i, dbl);
    }
    Accessoirement tu noteras ici une source de confusion: en effet, l'opérateur "étoile" quand il est écrit dans une déclaration de variable signifie "adresse de" et quand il est écrit dans une instruction signifie "pointe vers". Donc à toi de te souvenir de la nuance.

    Si maintenant la variable initiale est elle-même un pointeur ; ben la règle ne change pas (là aussi on rajoute "étoile" derrière son type). La variable étant (par exemple) du type "maPersonne étoile", alors l'adresse de cette variable sera du type "maPersonne étoile étoile".
    Et dans la fonction, là non plus la règle ne change pas. Si on veut faire référence à la variable d'origine, alors il faudra écrire "pointé de" en utilisant l'opérateur "étoile".

    D'où l'exemple de dalfab
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void creer_tab( int dim , mapersonne** ptab /* La variable d'origine étant un pointeur, son adresse sera un "pointeur étoile" */) {
        mapersonne *tab = malloc( dim * sizeof(mapersonne) ); // tab est locale
       (*ptab) = tab; // on remplit le "pointé de ptab" donc le pointeur dont on a reçu l'adresse
    }
    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]

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2011
    Messages : 10
    Points : 9
    Points
    9
    Par défaut
    bonsoir dalfab, bonsoir Sve@r,

    Merci pour vos explications claires et structurées.
    Je les ai mises en œuvre et maintenant, mon programme compile et s'exécute.

    Encore merci pour votre aide.

    Comme je suis autant débutant en "Forum" qu'en langage C, je peine un peu au niveau des conventions à mettre en oeuvre; mais je vais m'y mettre.

    getud78

    Citation Envoyé par Matt_Houston Voir le message
    Peux-tu insérer le code du programme entre balises [code] ? Sa consultation en deviendra plus aisée pour tout un chacun.
    Bonsoir Matt_Houston,

    Merci de me le faire remarquer; comme c'est la première fois que je transmet du code dans un forum, je n'ai pas encore les bons réflexes.

    Je vais d'ailleurs voir s'il est possible de transmettre le fichier c en P.J.

    Cordialement,

    getud 78

  6. #6
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Tu as déjà employé la pièce jointe dans ton premier post. Je te proposais d'inclure le code directement au sein du message, comme l'ont fait les autres intervenants.

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2011
    Messages : 10
    Points : 9
    Points
    9
    Par défaut tableaux de structures en argument
    Citation Envoyé par dalfab Voir le message
    Bonjour,

    La valeur du pointeur tab_pers_2 est transmise à la fonction créer_tab() qui met à jour sa copie qui s'appelle tab.
    Ensuite main() utilise tab_pers_2 qui n'a pas changée (donc qui vaut toujours NULL) et l'utiliser va planter.

    Une fonction ne peut pas modifier une données externe, transmettre l'adresse de tab_pers_2 est indispensable
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /*...*/
    void creer_tab( int dim , mapersonne** ptab ) {
    /*...*/
        mapersonne *tab = malloc( dim * sizeof(mapersonne) ); // tab est locale
       *ptab = tab; // on met à jour via pointeur la variable de l'appelant
    /*...*/
    }
     
    int main() {
    /*...*/
       creer_tab( nb_pers , &tab_pers_2 );
    /*...*/
    }
    Ou bien on fait l'inverse, c'est plus simple : la fonction créer_tab() calcule un tab, en retourne la valeur. Et cette valeur de retour est à copier dans tab_pers_2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*...*/
    mapersonne* creer_tab( int dim ) {
        mapersonne *tab;
    /*...*/
       return tab;
    }
     
    int main() {
    /*...*/
       tab_pers_2 = creer_tab( nb_pers );
    /*...*/
    }
    Bonsoir,

    Merci pour ces explications qui m'ont fait comprendre les erreurs que j'avais faites.
    Je intégré ces concepts dans mon code et tout fonctionne parfaitement.

    Cela m'a été d'une grande aide,

    Cordialement,

    getud78

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

Discussions similaires

  1. remplir un tableau de structure via une fonction
    Par B65AcR dans le forum Débuter
    Réponses: 2
    Dernier message: 07/01/2014, 17h06
  2. Réponses: 5
    Dernier message: 29/11/2012, 19h21
  3. Réponses: 7
    Dernier message: 03/10/2008, 11h37
  4. Réponses: 2
    Dernier message: 12/05/2007, 01h57
  5. tableau javascript ecrit par une fonction asp
    Par LineLe dans le forum ASP
    Réponses: 4
    Dernier message: 03/11/2003, 08h38

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