Created
June 20, 2022 13:24
-
-
Save the-moog/0487050449abcd9af623d09623048566 to your computer and use it in GitHub Desktop.
Sidestepping limitation of variable length member of fixed array sizes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> // for printf | |
#include <string.h> // for strcmp | |
// Define a card | |
typedef struct card | |
{ | |
int value; // This is an int, so it's storage size does not change | |
char * name; // This is a pointer, so it's storange size does not change | |
int rule_change; | |
} card_t; | |
// Example: | |
/* | |
card_t test = {1, "test", 0}; | |
card_t test_ary[] = {{1, "test", 0}, {1, "test", 0}}; | |
*/ | |
// Define an array of card_t pointers | |
typedef card_t * cards_t[]; | |
// Use a macro to save lots of typing | |
#define MKCARD(VAL, NAME) &(card_t){VAL, NAME, 0} | |
// Make the data an array of pointers to the data, the macro also adds defaults for us | |
#define CARD_INITIAL_VALUES { MKCARD(2, "Two"), MKCARD(3, "Three"), MKCARD(4, "Four"), MKCARD(5, "Five"), MKCARD(6, "Six"), MKCARD(7, "Seven"), \ | |
MKCARD(8, "Eight") , MKCARD(9, "Nine") , MKCARD(10, "Ten"), MKCARD(11, "Jack"), MKCARD(12, "Queen"), MKCARD(13, "King"), MKCARD(14, "Ace") } | |
// Create storage - note it is not necessary that all the suits are the same!! | |
cards_t suit_spades = CARD_INITIAL_VALUES; | |
cards_t suit_clubs = CARD_INITIAL_VALUES; | |
cards_t suit_diamonds = CARD_INITIAL_VALUES; | |
cards_t suit_hearts = CARD_INITIAL_VALUES; | |
// Define a suit | |
typedef struct suit | |
{ | |
char * name; | |
unsigned n_cards; // Information only structure does not depend on this | |
// card_t cards[N_CARDS] // We could say this but that would fix the number of cards in every game | |
card_t ** cards; // Instead pointer arrays make it more flexible and make little change to the code | |
} suit_t; | |
// Example: | |
/* | |
suit_t suit = { | |
.name = "Toy Cards", | |
.n_cards = 3, | |
.cards = (cards_t){ &(card_t){2, "duck"}, &(card_t){3, "goose"}, &(card_t){4,"eagle"}} | |
}; | |
*/ | |
// Instead of counting memory we are counting pointers | |
// That way each array of pointers can be different | |
#define COUNT_CARDS(SUIT) ((unsigned)(sizeof(SUIT)/sizeof(card_t *))) | |
suit_t mygame_deck[] = { | |
{ | |
.name = "Spades", | |
.n_cards = COUNT_CARDS(suit_spades), | |
.cards = suit_spades | |
}, { | |
.name = "Clubs", | |
.n_cards = COUNT_CARDS(suit_clubs), | |
.cards = suit_clubs | |
}, { | |
.name = "Diamonds", | |
.n_cards = COUNT_CARDS(suit_diamonds), | |
.cards = suit_diamonds | |
}, { | |
.name = "Hearts", | |
.n_cards = COUNT_CARDS(suit_hearts), | |
.cards = suit_hearts | |
} | |
}; | |
// Here we count memory as each array member is always the same size | |
#define N_SUITS ((unsigned)(sizeof(mygame_deck)/sizeof(typeof(0[mygame_deck])))) | |
// Demonstrate we are not using const so our array are not fixed | |
int game_rule_change(char *card, char *suit, int new_value) | |
{ | |
for (unsigned isuit=0; isuit < N_SUITS; isuit++) | |
for (unsigned icard = 0; icard < mygame_deck[isuit].n_cards; ++icard) | |
if ( strcmp(mygame_deck[isuit].name, suit) == 0 && | |
strcmp(mygame_deck[isuit].cards[icard]->name, card) == 0) | |
{ | |
mygame_deck[isuit].cards[icard]->value = new_value; | |
mygame_deck[isuit].cards[icard]->rule_change = 1; | |
return 1; | |
} | |
return 0; | |
} | |
int main(void) | |
{ | |
unsigned total_cards = 0; | |
for (unsigned isuit=0; isuit < N_SUITS; isuit++)total_cards += mygame_deck[isuit].n_cards; | |
printf("This game has %d suites\n", N_SUITS); | |
printf("You should have %u cards in the game\n", total_cards); | |
printf("\nList of cards:\n"); | |
game_rule_change("Five", "Hearts", 200); | |
for (unsigned isuit=0; isuit < N_SUITS; isuit++) | |
{ | |
printf(" Suit: %s (%u cards)\n", mygame_deck[isuit].name, mygame_deck[isuit].n_cards); | |
for (unsigned icard = 0; icard < mygame_deck[isuit].n_cards; ++icard) | |
{ | |
printf(" The card \'%s of %s\' has the value of %d%s\n", | |
mygame_deck[isuit].cards[icard]->name, | |
mygame_deck[isuit].name, | |
mygame_deck[isuit].cards[icard]->value, | |
mygame_deck[isuit].cards[icard]->rule_change?" - The rules have changed!!":""); | |
} | |
printf("\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment