Structures and pointers

typedef enum
{
SPADES,
HEARTS,
DIAMONDS,
CLUBS,
NUM_SUITS
} suit_t;

struct card_tag
{
unsigned value;
suit_t suit;
};

struct deck_tag
{
card_t  **cards;
size_t n_cards;
};

In struct deck_tag, why use ** cards.
I get error:

 request for member ‘suit’ in something not a structure or union

card_t **cards is a pointer to a pointer to a card_t. This probably means that you have an array of n_cards pointers, where each pointer points to a card_t. But we need to see the functions that handle these types to tell you more.

As for the error, I notice that you have both card_tag and card_t in your code and I surmise these should match, but again, we need to see the actual procedural code, not just the type declarations, to help you.

card_t is typedef to card_tag.
i need to write a function that prints card if it is the range.
so how to print cards which is in dec_tag structure

I Got it right but i dont understand how ** creates an array of pointers.Its like defining card_t cards[num] right.
I should write :

struct deck_tag deck     
deck.cards[0]->suit

No, it’s like defining card_t *cards[num] – note the asterisk.

The second line should work.

The relation between arrays and pointers is somewhat subtle. card_t **cards doesn’t “create” an array of pointers to objects of type card_t. It’s a pointer to the memory location of the first slot in an array of pointers. In order to use that array without blowing up everything you need to know the size of the array, which you have stored in n_cards.

Why you would do this

Let’s assume you want to store a number of objects of type card_t. If you use “normal” arrays the compiler needs to know the number of elements before the program runs:

# create an array that holds 10 objects of type card_t
card_t cards[10];

With pointers you can handle dynamically sized arrays where the number of elements is not known at compile time:

# determine the number of cards at run time
size_t n_cards = get_number_of_cards();

# allocate memory for that many objects of type card_t dynamically
card_t *cards = malloc(n_cards * sizeof(card_t));

# use the pointer like an array
cards[i].suit...

# clean up after use
free(cards);

Now, I have no idea why you are storing pointers to cards instead of the card objects themselves, but if you need to do this, you’ll get two levels of pointers: one to the start of the array, and one from the array to the actual object.

# allocate memory for pointers to objects of type card_t dynamically
card_t **cards = malloc(n_cards * sizeof(card_t*));

# use the pointer like an array, dereferencing the stored pointer to get a data field
cards[i]->suit...

# clean up after use
free(cards);