Reputation: 51
I have the following 3 structs for a card game program
// Linked list of cards, used for draw & discard pile, players' hands
typedef struct cardStack {
struct cardStack *next;
Card *card;
} CardStack;
// A player and their hand
typedef struct player {
int playerNumber;
CardStack *hand;
} Player;
typedef struct _game {
CardStack *discardPile;
CardStack *drawPile;
Player *players[4];
int currentPlayer;
int currentTurn;
} *Game;
and this function to initialise the game struct
Game newGame(int deckSize, value values[], color colors[], suit suits[]) {
Game game = (Game)malloc(sizeof(Game));
game->players[0] = (Player*)malloc(sizeof(Player));
game->players[0] = &(Player){0, NULL};
game->players[1] = (Player*)malloc(sizeof(Player));
game->players[1] = &(Player){1, NULL};
game->players[2] = (Player*)malloc(sizeof(Player));
game->players[2] = &(Player){2, NULL};
game->players[3] = (Player*)malloc(sizeof(Player));
game->players[3] = &(Player){3, NULL};
for (int i = 1; i <= 7; i++) {
for (int j = 1; i <= NUM_PLAYERS; i++) {
Card card = newCard(values[i * j - 1], colors[i * j - 1], suits[i * j - 1]);
addToStack(card, game->players[j-1]->hand);
}
}
CardStack *discardPile = (CardStack*)malloc(sizeof(CardStack));
Card firstDiscard = newCard(values[28], colors[28], suits[28]);
addToStack(firstDiscard, discardPile);
game->discardPile = discardPile;
CardStack *drawPile = (CardStack*)malloc(sizeof(CardStack));
for (int i = 29; i < deckSize; i++) {
Card card = newCard(values[i], colors[i], suits[i]);
addToStack(card, drawPile);
}
game->drawPile = drawPile;
game->currentPlayer = 0;
game->currentTurn = 1;
return game;
}
It compiles fine, but when I try to run it, this line
game->players[0] = (Player*)malloc(sizeof(Player));
and similar, give an error "illegal array, pointer or other operation" I'm not sure whats wrong as I am just setting one pointer (in the array of pointers in the struct) to another
EDIT: unfortunately this is an assignment where the header file was given so I have no choice but to use the pointer typedef
Upvotes: 1
Views: 155
Reputation: 753870
Quite apart from the memory allocation issue identified by John Kugelman, you have at least one more major problem…
Note that the lines like these two:
game->players[0] = (Player*)malloc(sizeof(Player));
game->players[0] = &(Player){0, NULL};
carefully leak the allocated memory. You replace the just allocated pointer with a pointer to the compound literal, which leaves you no way to free the allocated memory. It is perfectly legitimate to modify the compound literal as long as it doesn't go out of scope — but it does go out of scope when the function returns, so you not only leak memory but you also modify data you no longer own if you ever change the player information.
You probably want this instead, which copies the compound literal to the allocated memory:
game->players[0] = (Player*)malloc(sizeof(Player));
*game->players[0] = (Player){0, NULL};
I wouldn't be surprised to find there are other issues lurking, but the code is not an MCVE (Minimal, Complete, Verifiable Example) so it is hard to be sure.
Upvotes: 2
Reputation: 361615
typedef struct _game {
...
} *Game;
Game
is defined as an alias for struct _game *
, a pointer.
Game game = (Game)malloc(sizeof(Game));
That means that sizeof(Game)
is the size of a pointer and not the entire struct. A pointer is smaller than the entire struct, so it's not enough memory. Writing to ->players
accesses memory outside of the malloc'ed area which causes the illegal operation error.
A correct allocation would be:
Game game = malloc(sizeof *game);
Lesson learned: use p = malloc(sizeof *p)
rather than p = malloc(sizeof(Type))
to avoid this kind of mistake. The compiler won't catch a size mismatch. sizeof *p
will always be the right size, even if p
changes type.
And if possible, get rid of the *
in the definition of Game
! It's quite out of place.
Upvotes: 3
Reputation: 2027
Don't use pointers at the end of struct definitions it's ugly.
Change it to:
typedef struct _game {
CardStack *discardPile;
CardStack *drawPile;
Player *players[4];
int currentPlayer;
int currentTurn;
} Game;
And in your malloc
replace that statement with the following:
Game* games = (Game*)malloc(sizeof(Game));
Bonn-appetite!
Upvotes: 0