1

I'm working on a project for school:

I have to create a function with this prototype:

int ddg_add_player(ddg_t *ddg, player_t *player); 

Here is ddg_t struct :

typedef struct
{
        int day; /**< The DDG date (day). */
        char *dmname; /**< The dungeon master name. */
        int month; /**< The DDG date (month). */
        char *name; /**< The DDG name. */
        int nplayers; /**< The DDG number of players. */
        player_t **players; /**< The DDG players. */
        int year; /**< The DDG date (year). */
} ddg_t;

So I have to add filled player_t structures to a ddg_t structure. And I don't know how to process,

I tried with

ddg->players->ac = player->ac;

But it's obviously not working.

Just for this example let's say player_t is as follows:

typedef struct
{
        int ac; /**< The player armor class. */
} player_t;

I don't know why I have to use this player_t **players and I can't ask my teacher since I'll be evaluated on this project.

On another note, I do have an array of structure player_t, since I have multiple players.

Initially I thought I had to pass one structure at the time and my call looked like this:

for(i = 0; i < nPlayers; i++) {
        ddg_add_player(&ddg, &players[i]);
    }

My call now looks like this:

ddg_add_player(&ddg, players); /* players is my array of struct */

and the function like this :

int ddg_add_player(ddg_t *ddg, player_t *player){
    ddg->players = malloc(sizeof(player_t) * 3); /* i have 3 players */
    ddg->players[0]->ac = player[0].ac;
    printf("%d\n", ddg->players[0]->ac); /* just to check */

    return 0;
}

So, the code works, but in the header given by the teacher it says I have to add one player at the time.

Is there a way to do that?

I tried your solution @chmike but it gives me this error :

error: expected expression before ‘player_t’
 oc(ddg->players, (ddg->nplayers+1)*sizeof(*player_t));
                                            ^~~~~~~~

I tried to remove the * but then it gives me a segmentation fault.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
meshanda
  • 29
  • 4
  • You'll have to ask your teacher why you need the `player_t **`. Because that suggests an array of pointers to players, while it sounds like you just need an array of players. – Lundin Dec 09 '19 at 11:53
  • This appears very similar to _[the problem addressed here](https://stackoverflow.com/questions/5837772/gsoap-generated-client-side-structure-initialization-and-use)_, where in this case there is essentially header information, (collection of members describing the event.) and then an unknown (at compile-time) number of players participating in the event. And I have to agree with @Lundin, I do not see why a pointer to pointers is necessary. It would be interesting (after you have submitted this for credit of course.) if you could update your question with what your teacher was after. – ryyker Dec 09 '19 at 13:12

2 Answers2

2

I assume you are using the "pointer to pointer element" player_t **players to store an array of pointers to multiple players here?

In which case essentially the issue is given ddg->players->ac it doesn't know which player you want, there is an extra level of indirection there. e.g. the first player will be ddg->players[0]->ac and the second player ddg->players[1]->ac.

Of course you need to also allocate and free ddg->players itself separately here, e.g. ddg->players = malloc(sizeof(player_t*) * 5) for 5 players. And then you need to assign each player pointer separately, e.g. ddg->players[0] = first_player where you created the player elsewhere.

ddg->players = malloc(sizeof(player_t*) * 2)
ddg->players[0] = amy;
ddg->players[1] = bill;
printf("%d %d", ddg->players[0]->ac, ddg->players[1]->ac);

Now, if ddg_t should "own" the player_t with each only being used once, a player_t *players array could be used, getting rid of the extra indirection and allocation, but you should generally still always specify an index, even for the first item.

ddg->players = malloc(sizeof(player_t) * 3);
ddg->players[0].ac = 14;
ddg->players[1].ac = 18;
ddg->players[2].ac = 20;
Fire Lancer
  • 29,364
  • 31
  • 116
  • 182
  • No, `ddg->players = malloc(sizeof(player_t) * 5)` is not correct given the `player_t **` declaration. Which in turn doesn't make much sense, OP has to clarify. – Lundin Dec 09 '19 at 11:54
  • @Lundin yep, I missed a character. `T**` in this context really looks like an array of pointers. There could be many reasons, e.g. a player could be in multiple games. – Fire Lancer Dec 09 '19 at 11:55
1

In the ddg_t structure we see the fields

int nplayers; /**< The DDG number of players. */
player_t **players; /**< The DDG players. */

We can deduce from it that players is a pointer to pointers to player_t. players is thus an array of pointers to players and nplayers is the number of elements (pointers to player_t) in the array.

To add a new player you need to append it to the array of players. This implies the array needs to grow. This is performed by using the realloc function with the new byte size of the array as argument.

Here is the code of the function:

int ddg_add_player(ddg_t *ddg, player_t *player){
    ddg->players = realloc(ddg->players, (ddg->nplayers+1)*sizeof(*player_t));
    ddg->players[ddg->nplayers++] = player;
}

The first instruction grows the players array by one element at the end.

The second instruction assign player to the last element of the array after what it increments nplayers.

When the function terminates, players is the input array with player appended to it, and nplayers has been incremented since it contains one more player.

chmike
  • 20,922
  • 21
  • 83
  • 106