10

New to pointers and C and need for my program a pointer for an array of structs and be able to pass this pointer to a function.

What is the correct way to declare a pointer of struct array type and what should be my function parameter that can take such pointer?

This is my attempt:

#define HAND_SIZE 5

struct Card {
    char suit;
    char face;
};

void printHandResults(struct Card *hand[HAND_SIZE]);

int main(void)
{
    struct Card hand[HAND_SIZE];
    struct Card (*handPtr)[HAND_SIZE]; //Correct way to declare?
    handPtr = &hand; 
    ...
    printHandResults(handPtr);

}
void printHandResults(struct Card *hand[HAND_SIZE]) {
...
}

And this is the warning I get:

warning: incompatible pointer types passing 'struct Card (*)[5]' to parameter of type 'struct Card **' [-Wincompatible-pointer-types]

I understand the pointers are different types but I cant seem to figure out how to set it correctly.

I'll appreciate if someone can *pointer me in the right direction.

user2300867
  • 593
  • 1
  • 12
  • 28
  • Arrays automatically become pointers when they're passed to a function, you don't need a separate variable for this. – Barmar Nov 08 '16 at 01:57
  • 1
    `struct Card *hand[HAND_SIZE]` is an array of pointers, not a pointer to an array. – Barmar Nov 08 '16 at 01:58
  • handPtr in your way is array of pointer. Why wouldn't you just pass &hand to printHandResults? – khôi nguyễn Nov 08 '16 at 01:58
  • 1
    Why do you want a pointer to an array? Arrays are usually manipulated using pointers to the element type, not to the array as a whole. That's not to say that array pointers are never useful, but element pointers are far more common. – Keith Thompson Nov 08 '16 at 02:46
  • @KeithThompson - He may need to change the array in the callee. – jww Nov 09 '16 at 06:45
  • @jww: Yes, and the usual way to do that is via a pointer to the element type. – Keith Thompson Nov 09 '16 at 08:01

3 Answers3

6

Maybe what you want is to do this:

void printHandResults(struct Card (*hand)[]);

and this:

void printHandResults(struct Card (*hand)[]) {

}

What you were doing was passing a pointer to an array of struct variables in the main, BUT, the function was set to receive an array of pointers to struct variables and not a pointer to an array of struct variables! Now the type mismatch would not occur and thus, no warning.

Note that [], the (square) brackets have higher precedence than the (unary) dereferencing operator *, so we would need a set of parentheses () enclosing the array name and * operator to ensure what we are talking about here!

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
skrtbhtngr
  • 2,223
  • 23
  • 29
6

An array degrades into a raw pointer to the first array element. So you can do something more like this instead:

#define HAND_SIZE 5

struct Card {
    char suit;
    char face;
};

void printHandResults(struct Card *hand);

int main(void)
{
    struct Card hand[HAND_SIZE];
    ...
    printHandResults(hand);
}

void printHandResults(struct Card *hand)
{
    for (int i = 0; i < HAND_SIZE; ++i)
    {
        // print hand[i].suit and hand[i].face as needed...
    }
}

Alternatively:

#define HAND_SIZE 5

struct Card {
    char suit;
    char face;
};

void printHandResults(struct Card *hand, int numInHand);

int main(void)
{
    struct Card hand[HAND_SIZE];
    ...
    printHandResults(hand, HAND_SIZE);
}

void printHandResults(struct Card *hand, int numInHand)
{
    for (int i = 0; i < numInHand; ++i)
    {
        // print hand[i].suit and hand[i].face as needed...
    }
}

Alternatively, create a new typedef for the card array, and then you can create variables and pointers of that type:

#define HAND_SIZE 5

struct Card {
    char suit;
    char face;
};

typedef struct Card Hand[HAND_SIZE];

void printHandResults(Hand *hand);

int main(void)
{
    Hand hand;
    ...
    printHandResults(&hand);
}

void printHandResults(Hand *hand)
{
    for (int i = 0; i < HAND_SIZE; ++i)
    {
        // print hand[i].suit and hand[i].face as needed...
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks this makes sense.Why the second int parameter? – user2300867 Nov 08 '16 at 02:07
  • The second parameter is to know the size of the actual array in the called function. – skrtbhtngr Nov 08 '16 at 02:12
  • I see. But given I already have it as a constant HAND_SIZE and could use it from function body do I still need it as a parameter in the function? Please explain. – user2300867 Nov 08 '16 at 02:16
  • 1
    Sure, if you always have `HAND_SIZE` number of cards in the hand being printed. But having the second parameter allows the function to be more flexible so it can print different hand sizes. Say you want to print the cards before a full hand is dealt. Or you want to implement multiple card games that use different number of cards per hand. – Remy Lebeau Nov 08 '16 at 02:35
0

More easy way:

#define HAND_SIZE 5

typedef struct Cards{
   char suit;
   char face;
}card_t;

void printHandResults( card_t*);

int main(void)
{
   card_t hand[HAND_SIZE];
   card_t* p_hand = hand;
...
   printHandResults(p_hand);

}
void printHandResults( card_t *hand)
{
 // Here you must play with pointer's arithmetic 
...
}