Tableau structures argument de fonctions :retour

Résolu/Fermé
getudir78 Messages postés 29 Date d'inscription vendredi 3 janvier 2014 Statut Membre Dernière intervention 2 septembre 2020 - Modifié le 13 juin 2018 à 16:09
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 - 14 juin 2018 à 23:25
/*
le programme compile et s'execute partiellement

lorsque allocation de memoire et initialisation des champs
sont realisees directement dans le main, ce programme fonctionne bien

lorsque allocation de memoire et initialisation des champs
sont realisees a l'aide d'une fonctions, tout semble bien se passer dans la fonction
mais apres cela, le tableau de structures n'est pas accessible dans le main

merci de m'aider a trouver l'erreur
  • /

#include <stdio.h>
#include<stdlib.h>
typedef struct personne
{
  char nom[15];
  int age;
  float poids;
} mapersonne;

void creer_tab (int dim, mapersonne *tab) {
 /*mmm initialise le tableau de structures */
 int i;
 printf("char = %d\n",sizeof(char));
 printf("int = %d\n",sizeof(int));
 printf("dim = %d\n",sizeof(float));
 printf("mapersonne sizeof = %d\n", sizeof(mapersonne));
 //
 tab = malloc(dim*sizeof(mapersonne));
 
 i = 0;
 while ( i < dim) {
  printf("donnez un nom - un age - un poids\n");
  scanf("%s", tab[i].nom);
  scanf("%d", &(tab[i].age));
  scanf("%f", &(tab[i].poids));
  printf("dans fonction creer_tab : nom = %s age = %d poids = %f\n",tab[i].nom, tab[i].age, tab[i].poids);
  i++;
 }
 return ;
}

int main() {
 int nb_pers, i;
 // pointeur defini pour l'allocation dynamique de memoire
 mapersonne *tab_pers_1 = NULL;
 mapersonne *tab_pers_2 = NULL;
 //
 printf ("nombre de personnes a definir ?\n");
 scanf("%d", &nb_pers);
 //
 // debut creation tab_pers_1 directement dans main() - tout fonctionne parfaitement
 printf("debut de l'initialisatio du tableau de structures directement dans main()\n");
 tab_pers_1 = malloc(nb_pers*sizeof(mapersonne));
 //
 i = 0;
 while ( i < nb_pers) {
  printf("donnez un nom - un age - un poids\n");
  scanf("%s", tab_pers_1[i].nom);
  scanf("%d", &(tab_pers_1[i].age));
  scanf("%f", &(tab_pers_1[i].poids));
  i++;
 }
 // impression de valeurs definies ci-dessus
 for (int i = 0;i<nb_pers;i++) {
  printf("nom : %s age = %d poids =  %f\n",tab_pers_1[i].nom, tab_pers_1[i].age, tab_pers_1[i].poids);
 }
 printf("fin de l'initialisation du tableau de structures directement dans main()\n");
 // fin creation tab_pers_1 directement dans main() - tout fonctionne parfaitement
 //
 //debut creation tab_pers_2 par la fonction creer_tab - probleme :
 // les valeurs initialsees dans creer_tab(...) ne sont pas connues dans fonction creer_tab
 printf("\ndebut de l'initialisation du tableau de structures par la fonction creer_tab\n");
 //
 creer_tab (nb_pers, tab_pers_2);
 //
 //impression des valeurs retournees dans le main()
 // dans l'etat actuel du programme, 
 for (int i = 0;i<nb_pers;i++) {
  printf(" valeurs retournees de creer_tab personne numero : %d nom : %s",i, tab_pers_2[i].nom);
  printf(" age = %d", tab_pers_2[i].age);
  printf(" poids = %f\n",tab_pers_2[i].poids);
 }
 printf("fin de l'initialisation du tableau de structures par la fonction creer_tab\n");
 //fin creation tab_pers_2 par la fonction  - probleme :
 // les valeurs initialsees dans creer_tab(...) ne sont pas commues dans le main
 //
 return 0;
}

1 réponse

[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 14 juin 2018 à 11:10
Salut getudir78,

Dans main
mapersonne *tab_pers_2 = NULL;
, tab_pers_2 est une variable pointeur et la valeur contenue par cette variable est NULL.

Or, tu passes cette variable à
creer_tab()
.

Comme tout passage de variable, en C, le passage d'une variable opère une copie de cette variable, sur laquelle travaille la fonction.

Donc, dans ta fonction
creer_tab()
, lorsque tu alloues de la mémoire et que tu ranges l'adresse mémoire du bloc alloué, tu ranges l'adresse dans une autre variable pointeur (la copie), et donc la variable pointeur déclarée dans main() n'est pas modifiée et continue de pointer vers NULL.

Dal
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 14 juin 2018 à 11:21
Pour résoudre ce problème, tu pourrais changer ton prototype et passer un pointeur sur un pointeur sur struct, et ensuite déréférencer correctement ce pointeur.

Cependant, puisque tu alloues la mémoire dans ta fonction, le passage du pointeur n'a pas trop d'intérêt, et tu te compliques vraiment la vie.

Alors, une façon beaucoup plus simple de faire est de passer juste le nombre de personnes à créer et que
creer_tab()
retourne un pointeur sur mapersonne.

Quelque chose comme cela :

#include <stdio.h>
#include <stdlib.h>

typedef struct personne {
    char nom[15];
    int age;
    float poids;
} mapersonne;

mapersonne * creer_tab(int dim) {
    int i = 0;
    mapersonne * tab = NULL;

    tab = malloc(dim * sizeof(mapersonne));
    for (i = 0; i < dim; i++) {
        printf("donnez un nom - un age - un poids\n");
        scanf("%s", tab[i].nom);
        scanf("%d", &tab[i].age);
        scanf("%f", &tab[i].poids);
    }

    return tab;
}

int main(void) {
    int nb_pers, i;
    mapersonne * tab = NULL;
    
    printf ("nombre de personnes a definir ?\n");
    scanf("%d", &nb_pers);

    tab = creer_tab(nb_pers);

    for (i = 0; i < nb_pers; i++) {
        printf(" valeurs retournees de creer_tab personne "
                "numero : %d nom : %s", i, tab[i].nom);
        printf(" age = %d", tab[i].age);
        printf(" poids = %f\n", tab[i].poids);
    }
    free(tab);

    return 0;
}

Une autre façon simple de faire serait de garder ton prototype
void creer_tab (int dim, mapersonne *tab)
, mais d'opérer l'allocation mémoire dans
main()
et donc de laisser à la fonction appelante de
creer_tab()
la responsabilité d'allouer la mémoire.

Il y a une certaine logique à cette dernière approche, car la fonction appelante est aussi responsable de la libération de la mémoire (le
free()
, que tu avais d'ailleurs omis dans ton code).

Dal
0
Merci pour tes explications limpides. J'ai implémenté la première démarche et compilation comme exécution se passent parfaitement bien.
Mon problème est donc résolu!
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
14 juin 2018 à 23:25
Génial, je suis content !

En ce qui me concerne, la première approche me rend un peu nerveux ;-)

Je lui préfère la dernière approche, qui permet de dissocier l'allocation mémoire de l'usage de l'espace alloué par la fonction. Cela me permet de mettre, dans la même fonction appelante, le
malloc()
et le
free()
... et cela me rassure de pouvoir, autant que possible, voir les deux dans la même fonction :-)
0