structures et pointeurs nesteds

Je raconte ça à peu près à chaque fois que je retourne dans un projet C. Une erreur de segmentation se crée lorsque j’essaie d’accéder à une structure dans une structure. Disons que j’ai les structures (simplifiées) suivantes pour un jeu:

struct vector { float x; float y; }; struct ship { struct vector *position; }; struct game { struct ship *ship; } game; 

Et une fonction pour initialiser le vaisseau:

 static void create_ship(struct ship *ship) { ship = malloc(sizeof(struct ship)); ship->position = malloc(sizeof(struct vector)); ship->position->x = 10.0; } 

Puis dans main ():

 int main() { create_ship(game.ship); printf("%f\n", game.ship->position->x); // <-- SEGFAULT } 

Vous game.ship par valeur. Ainsi, à l’intérieur de create_ship la variable ship est simplement une copie de ce pointeur et elle ne fait que modifier la copie. Lorsque la fonction revient, le pointeur sur ce que vous avez malloc ed est perdu et les effets de la fonction ne sont pas visibles en dehors de celle-ci, sauf pour la fuite de mémoire.

Vous devez passer un pointeur sur le pointeur et modifier game.ship travers cela:

 static void create_ship(struct ship **ship) { *ship = malloc(sizeof(struct ship)); (*ship)->position = malloc(sizeof(struct vector)); (*ship)->position->x = 10.0; } 

Et

 create_ship(&game.ship); 

Ou peut-être une meilleure façon serait-elle, comme le suggère Johnny Mopp dans les commentaires, de renvoyer le pointeur depuis la fonction au lieu d’en modifier un en dehors:

 static struct ship* create_ship() { struct ship* s = malloc(sizeof(struct ship)); s->position = malloc(sizeof(struct vector)); s->position->x = 10.0; return s; } 

Et

 game.ship = create_ship(); 

Et bien sûr, ce que vous avez en malloc , n’oubliez pas de free .

Vous devriez passer par référence:

 static void create_ship(struct ship **ship); 

et

 create_ship(&game.ship); 

sinon, la structure allouée est ignorée.

Votre fonction create_ship ne change pas réellement game.ship , car l’argument est passé par valeur . Dans la fonction create_ship , seule une copie est en cours de modification. Donc après l’appel, game.ship rest non initialisé (ou NULL , ou quelle que soit sa valeur est avant l’appel). Par conséquent, vous perdez également la référence au navire nouvellement alloué et perdez de la mémoire.

Vous devrez passer un pointeur à un pointeur pour le changer:

 static void create_ship(struct ship **ship) { *ship = malloc(sizeof(struct ship)); // ... 

Et dans l’appel: create_ship(&game.ship);

Vous pouvez également choisir de transmettre le nouveau navire en tant que valeur de retour de la fonction:

 static ship *create_ship() { struct ship *ship = malloc(sizeof(struct ship)); // ... return ship; } // ... game.ship = create_ship();