2012-02-27 4 views
2

j'ai un struct comme siTableau de pointeurs sur struct

typedef struct person { 
int id; 
char name[20]; 
} Person; 

Puis, en dehors de la fonction, j'ai un tableau de pointeurs de pointeurs vers ces struct, comme si

Person **people; 

Puis, en la fonction que je suis ajout de personnes à l'ensemble comme si (dans une boucle)

Person person; 

for (i = 0; i < 50; i++) 
{ 
    person.id = i; 
    person.name = nameArray[i]; 
    people[i] = &person; 
} 

person est ajouté au people tableau mais quand (dans VS2010) je vais à l'écran de surveillance et tapez people, 50 Je vois juste le même person dans chaque emplacement comme si lors de l'ajout de la personne suivante, il change tous les précédents. Qu'est-ce que je fais mal ici?

De même, pour récupérer le nom d'une certaine personne, est-ce la bonne syntaxe?

people[0] -> name; Ou est-ce people[0][0].name?

Merci!

+1

Sidenote sur une question supprimée: J'écrivais juste une réponse à votre question http://stackoverflow.com/questions/9485491/read-string-from-stdin-maintain-string-length lorsque vous l'avez supprimée. –

+0

Désolé pour ça. Il se peut que cela n'ait pas été une question très productive pour le site. –

+0

Nevermind. L'idée était: Mettre tout le 'char [20]' sur tout ''\ 0' 'avant d'appeler' fscanf'. Après le retour de 'fscanf', faites' for (int i = 19; i> = 0; i--) {if (s [i] == '\ 0') s [i] = ''; autre casse;} '. –

Répondre

9

Qu'attendez-vous? Vous faites pointer tous les pointeurs vers le même Person. Et lorsque person est hors de portée, tous les pointeurs de votre tableau (qui sont tous les mêmes) seront invalides et pointeront vers un bloc de mémoire désalloué. Vous devez utiliser malloc à chaque itération de la boucle pour allouer de la mémoire dynamique et créer un Person qui ne disparaîtra pas jusqu'à ce que vous free il:

for (i = 0; i < 50; i++) 
{ 
    Person *person = malloc(sizeof(Person)); 
    person->id = i; 
    person->name = nameArray[i]; 
    people[i] = person; 

    /* or: 
    people[i] = malloc(sizeof(Person)); 
    people[i]->id = i; 
    people[i]->name = nameArray[i]; 

    it does the same thing without the extra temporary variable 
    */ 
} 

// then when you are done using all the Person's you created... 
for (i = 0; i < 50; ++i) 
    free(people[i]); 

Sinon, vous pourriez avoir un tableau de Person s au lieu de Person* s et ce que vous faites travailleraient:

Person people[50]; 

Person person; 

for (i = 0; i < 50; i++) 
{ 
    person.id = i; 
    person.name = nameArray[i]; 
    people[i] = person; // make a copy 
} 

et avec cette façon, vous n'avez pas à quoi que ce soit free.

+3

+1 Clair comme le cristal. – cnicutar

+0

@cnicutar Merci, venant de vous qui signifie quelque chose. –

2

Je vois tout de même « personne » dans chaque emplacement ...

droit, parce que vous utilisez le même Person chaque fois. Vous êtes réaffectant ses membres, de sorte que la dernière affectation reste et vos pointeurs pointent tous vers la même partie de la mémoire.

Sachez également que vous stockez l'adresse d'une variable avec la durée de stockage automatique (c'est-à-dire, la pile allouée). Cette mémoire sera (probablement) nettoyée lorsque la fonction se termine et déréférencer l'un de ces pointeurs plus tard entraînera un comportement indéfini.

Vous devez utiliser l'allocation dynamique si vous avez besoin d'initialiser le tableau dans la fonction et de le conserver valide lorsque la fonction se termine.

1

Vous avez à allouer de la mémoire pour chaque personne:

for (i = 0; i < 50; i++) 
{ 
    people[i] = (person*)malloc(sizeof(person)); // dynamic memory allocation 
    people[i]->id = i; 
    people[i]->name = nameArray[i]; 
} 

L'adresse &person de person ne change pas dans votre version originale, donc vous avez un tas de pointeurs pointant sur les mêmes données, qui changera le chaque itération.

0

Vous devez vous assurer d'allouer de l'espace pour chaque person. Votre code tel qu'il est actuellement n'a qu'une structure person que vous réutilisez, et tous ces pointeurs pointent vers la même adresse.

1

En raison de la façon dont vous avez écrit cela, vous avez initialisé chaque pointeur sur la même instance de la personne, examiner:

Person person; // this allocates a single person 

for (i = 0; i < 50; i++) 
{ 
    person.id = i; 
    person.name = nameArray[i]; 
    people[i] = &person; 
} 

Ce que vous devez faire est de répartir dynamiquement chaque personne, comme si:

for (i = 0; i < 50; i++) 
{ 
    Person* person = (Person*)malloc(sizeof(Person)); 
    person->id = i; 
    person->name = nameArray[i]; 
    people[i] = person; 
} 

ne pas oublier de libérer toute la mémoire une fois que vous avez terminé, donc à la fin de votre code:

int i; 
for (i=0; i<50; i++) 
    free(people[i]); 
free(people); 
0

Les autres réponses sont toutes correctes. La seule chose que je peux ajouter est, outre de ne pas créer un nouveau Person, vous l'allouez également sur la pile quand vous devriez utiliser le tas. Assurez-vous de comprendre pourquoi les éléments suivants « changement rapide » à votre code existant est mauvais:

for (i = 0; i < 50; i++) 
{ 
    Person person; /* <--- BAD. Make sure you understand why. */ 

    person.id = i; 
    person.name = nameArray[i]; 
    people[i] = &person; 
} 

Cela fait une nouvelle Person à chaque fois, en utilisant votre ancienne façon de créer personne. Encore une fois, s'il vous plaît assurez-vous de comprendre pourquoi c'est faux et les autres réponses (en utilisant malloc) ont raison.

Questions connexes