Thread: Having trouble understanding malloc + structs

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    22

    Having trouble understanding malloc + structs

    So, I have this code (taken from stackoverflow, not going to use it unless i can recreate and understand it)
    It's a program to make a deck of 52 cards and there are som things i just can't wrap my head around.


    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    typedef struct _card {
        int suit;
        int value;
    } card;
    
    
    typedef struct _deck {
        int num_cards;
        card **cards;
    } deck;
    
    
    card *make_card(int suit, int value)
    {
        card *newCard = malloc(sizeof(card));
        newCard->suit = suit;
        newCard->value = value;
    
    
        return newCard;
    }
    
    
    deck *make_standard_deck(void)
    {
        deck *newDeck = malloc(sizeof(deck));
    
    
        newDeck->num_cards = 52;
        newDeck->cards = malloc(52 * sizeof(card *));
    
    
        int index = 0;
        for (int suit = 0; suit < 4; suit++)
            for (int value = 1; value <= 13; value++)
                newDeck->cards[index++] = make_card(suit, value);
    
    
        return newDeck;
    }
    
    
    int main(void)
    {
        int i;
    
    
        deck *stdDeck = make_standard_deck();
    
    
        for (i = 0; i < stdDeck->num_cards; i++)
            printf("suit=%d value=%2d\n", stdDeck->cards[i]->suit, stdDeck->cards[i]->value);
    
    
        /* free the deck when we're done with it */
        for (i = 0; i < stdDeck->num_cards; i++)
            free(stdDeck->cards[i]);
        free(stdDeck->cards);
        free(stdDeck);
    }

    Code:
    typedef struct _deck {
        int num_cards;
        card **cards;
    } deck;
    What does the card **cards; do? I don't understand anything about this statement or why it's needed.


    Code:
        deck *newDeck = malloc(sizeof(deck));
    
    
        newDeck->num_cards = 52;
        newDeck->cards = malloc(52 * sizeof(card *));
    Need these lined explained aswell.


    Code:
    for (i = 0; i < stdDeck->num_cards; i++)
            printf("suit=%d value=%2d\n", stdDeck->cards[i]->suit, stdDeck->cards[i]->value);
    Here it looks like the program accesses the individual cards as if it was an array? How did the deck ever become an array?




    Sorry if my questions dont make sense or are simply dumb but really need help with this :/
    Thanks in advance!

  2. #2
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    When I started out with C (way back in the DOS days) I had a book "Teach Yourself C In 21 Days". It actually took me several years before it 'clicked'.

    I would consider that to be a fairly advanced program, in that to understand it you would need to have absolutely down pat such topics as manipulating dynamically allocated memory through pointers involving multiple levels of indirection. That's what your card** refers to. The 1st level of indirection involves allocating a memory block large enough to contain 52 pointers to card objects. Within each of those 'slots' another object will be allocated and the pointer to it stored there. Those objects will be pointers to card objects. So you have two levels of indirection. Like I said, this is fairly advanced stuff, and unless you've been at this for longer than 21 days ( ), it might come hard.

  3. #3
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    This...

    Code:
    newDeck->cards = malloc(52 * sizeof(card *));
    ...allocates a memory block large enough to hold 52 pointers. On 32 bit systems - 208 bytes, and on 64 bit systems - 416 bytes. A pointer to that block will be returned in newDeck->cards. This...

    Code:
    newDeck->cards[index++] = make_card(suit, value);
    ...which is in a double index for loop, will place within each of those 52 'slots' a pointer to a card object (returned from make_card).

    I never liked this C notation where this is done...

    char *pObj=NULL;

    I much prefer this instead....

    char* pObj=NULL;

  4. #4
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    Quote Originally Posted by freddie View Post
    When I started out with C (way back in the DOS days) I had a book "Teach Yourself C In 21 Days". It actually took me several years before it 'clicked'.

    I would consider that to be a fairly advanced program, in that to understand it you would need to have absolutely down pat such topics as manipulating dynamically allocated memory through pointers involving multiple levels of indirection. That's what your card** refers to. The 1st level of indirection involves allocating a memory block large enough to contain 52 pointers to card objects. Within each of those 'slots' another object will be allocated and the pointer to it stored there. Those objects will be pointers to card objects. So you have two levels of indirection. Like I said, this is fairly advanced stuff, and unless you've been at this for longer than 21 days ( ), it might come hard.
    Hm I see. How would I do it without using that stuff then?
    Since I'm eager to learn, let me know if you know where I can learn more about what you were talking about I think I understand the theory but not quite how it's happening in the code.

  5. #5
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    Quote Originally Posted by freddie View Post
    This...

    Code:
    newDeck->cards = malloc(52 * sizeof(card *));
    ...allocates a memory block large enough to hold 52 pointers. On 32 bit systems - 208 bytes, and on 64 bit systems - 416 bytes. A pointer to that block will be returned in newDeck->cards. This...

    Code:
    newDeck->cards[index++] = make_card(suit, value);
    ...which is in a double index for loop, will place within each of those 52 'slots' a pointer to a card object (returned from make_card).

    I never liked this C notation where this is done...

    char *pObj=NULL;

    I much prefer this instead....

    char* pObj=NULL;
    Okay I think I get the idea, but still not really the code..

  6. #6
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    I would personally avoid using a structure to describe each card; I'd prefer encoding the suit and the face into a single positive number. For example:
    Code:
    /* Suit is an integer 1 to 4, inclusive. */
    #define SUIT_SPADES  1
    #define SUIT_CLUBS  2
    #define SUIT_DIAMONDS  3
    #define SUIT_HEARTS 4
    
    /* Face is an integer 1 to 13 or 2 to 14. */
    #define FACE_2  2
    #define FACE_3  3
    #define FACE_4  4
    #define FACE_5  5
    #define FACE_6  6
    #define FACE_7  7
    #define FACE_8  8
    #define FACE_9  9
    #define FACE_10  10
    #define FACE_JACK  11
    #define FACE_QUEEN  12
    #define FACE_KING  13
    #define FACE_ACE 14 /* or 1, depending on game */
    
    /* This macro combines a suit and a face to a single positive integer (larger than zero, less than 80) */
    #define CARD(suit, face) (16*(suit) + (face))
    
    /* This macro yields the suit of a card */
    #define SUIT(card) ((card) / 16)
    
    /* This macro yields the face of a card */
    #define FACE(card) ((card) % 16)
    You can then use e.g. unsigned char type to describe each card; a deck could be unsigned char deck[52];.

    In numerical order, each suit is sorted consecutively, with spades first (lowest value) and hearts last (highest value). In other words, CARD(SUIT_HEARTS, FACE_QUEEN) > CARD(SUIT_HEARTS, FACE_JACK), but CARD(SUIT_HEARTS, FACE_2) > CARD(SUIT_SPADES, FACE_ACE).

    Writing just one or two helper functions, you can trivially sort decks using qsort(). For example, with
    Code:
    int by_suit_and_face(const void *ptr1, const void *ptr2)
    {
        const unsigned char  card1 = *(const unsigned char *)ptr1;
        const unsigned char  card2 = *(const unsigned char *)ptr2;
        const int  value1 = FACE(card1) - 16 * SUIT(card1));
        const int  value2 = FACE(card2) - 16 * SUIT(card2));
        return value1 - value2;
    }
    
    int by_face_and_suit(const void *ptr1, const void *ptr2)
    {
        const unsigned char  card1 = *(const unsigned char *)ptr1;
        const unsigned char  card2 = *(const unsigned char *)ptr2;
        const int  value1 = SUIT(card1) - 5 * FACE(card1);
        const int  value2 = SUIT(card2) - 5 * FACE(card2);
        return value1 - value2;
    }
    you can sort the aforementioned deck so that within each suit, the cards are in their face order, but hearts first, then diamonds, then clubs, and spades last:
    qsort(deck, sizeof deck, sizeof deck[0], by_suit_and_face);
    Conversely, if you want a deck with all four faces (of different suits) consecutive, use
    qsort(deck, sizeof deck, sizeof deck[0], by_face_and_suit);
    You can even construct an array of strings to describe each face and suit (but remember that we skip zero index):
    Code:
    static const char *const suit_name[] = {
        "", /* This corresponds to 0, which is no suit. */
        "spades",
        "clubs",
        "diamonds",
        "hearts",
    };
    
    static const char *const face_name[] = {
        "", /* This corresponds to 0, which is no face */
        "ace", /* For both 1 and 14, as you might use either one */
        "two",
        "three",
        "four",
        "five",
        "six",
        "seven",
        "eight",
        "nine",
        "ten",
        "jack",
        "queen",
        "king",
        "ace",
    };
    which lets you describe any card using
    printf("%s of %s", face_name[FACE(card)], suit_name[SUIT(card)]);
    which will print strings like ten of spades and ace of hears, for every possible card.



    When you don't need the string representation nor the qsort() helper functions, but you need additional speed -- say, you're investigating card shuffling or cyclic stuff, and deal with billions of cards -- you might change the definitions into
    Code:
    #define SUIT_SPADES  0
    #define SUIT_CLUBS  16
    #define SUIT_DIAMONDS  32
    #define SUIT_HEARTS 48
    
    #define COLOR_BLACK  0
    #define COLOR_RED  32
    
    #define CARD(suit, face) ((suit) | (face))
    #define SUIT(card) ((card) & 15)
    #define FACE(card) ((card) & 48)
    #define COLOR(card) ((card) & 32)
    which lets you extract and combine card features with just one binary AND or OR operator (which are fastest possible on all computer and microcontroller architectures that use binary arithmetic -- all, except for a few expensive museum curiosities).

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Finoli View Post
    Okay I think I get the idea, but still not really the code..
    I hope this helps but I don't know what you find confusing anymore. I'm relying on what you said here to be the problem:
    Since I'm eager to learn, let me know if you know where I can learn more about what you were talking about I think I understand the theory but not quite how it's happening in the code.
    If you want to know more about the code card **cards, I can tell by looking that it is intended to be a dynamic array. It just looks more complicated than usual because the array contains other objects stored on the heap; by which I mean all the pointers to cards that make_card(suit, value); returns.

    If allocating an array is still the most confusing part, then I suggest you read the following:




    Hm I see. How would I do it without using that stuff then?
    Happily, it can be done less complicated. The key to making a deck of cards is ultimately that each card is different and you need a deterministic way to find which suit it is, and which rank it is. A normal deck has 13 ranks and 4 suits, for 52 cards.

    You can even make a deck out of the integers 1 to 52, if you use some math. Take a look at these tables:
    Code:
    rank = card_id % 13
    
     2| 3| 4| 5| 6| 7| 8| 9| T| J| Q| K| A|
      |  |  |  |  |  |  |  |  |  |  |  |  |
     1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|
    14|15|16|17|18|19|20|21|22|23|24|25|26|
    27|28|29|30|31|32|33|34|35|36|37|38|39|
    40|41|42|43|44|45|46|47|48|49|50|51|52|
    
    suit = card_id % 4
    
        clubs|   spades|   hearts| diamonds|
            1|        2|        3|        4|
            5|        6|        7|        8|
            9|       10|       11|       12|
           13|       14|       15|       16|
           17|       18|       19|       20|
           21|       22|       23|       24|
           25|       26|       27|       28|
           29|       30|       31|       32|
           33|       34|       35|       36|
           37|       38|       39|       40|
           41|       42|       43|       44|
           45|       46|       47|       48|
           49|       50|       51|       52|

  8. #8
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    Hm I see. How would I do it without using that stuff then?
    Since I'm eager to learn, let me know if you know where I can learn more about what you were talking about I think I understand the theory but not quite how it's happening in the code.
    As others have said, that application could be done more easily without pointers and dynamic memory allocations. For example, dynamic memory allocations are only really necessary when it is not known until run-time the bounds of the data. In this case, we know at design time that a standard deck of cards contains 52 cards, and so on with suites and such. But if truth were to be known, its my guess the original author of that code did it to hone his skills at pointers and dynamic memory allocations in C. I say this because there is a very important 'design pattern' underlying that code which I consider it very, very worthwhile to learn, because it comes up in very many contexts. I struggled with it myself for quite a bit when I was learning this stuff, and if your goal is to learn programming techniques, I'd strongly urge you to understand it. However, if your goal is to simply make a game of cards, then perhaps you might want to take one of the easier routes. But if the former, here is a little program that essentially abstracts from the above code the underlying 'design pattern' which I've stated as being the essence of that code, and I believe it is the part you are having trouble coding and grasping...

    Code:
    /*
      Program shows very important 'design pattern' used frequently in low level
      coding in C/C++ and other low level capable languages involving pointers and
      two levels of indirection.  The program creates a memory block large enough
      to hold pointers to four strings.  That would be pMem of type char** below.
      Into each four byte slot (8 bytes for x64) another memory allocation is made
      for memory for the "zero", "One", "Two", and "Three" strings.  Then those
      strings are copied to that memory.  So the underlying idea is a memory block
      of some determinate size to hold or contain pointers to something.  And that
      'something' is application determined, although in this app it is simply
      null terminated strings.  So pMem holds or points to a memory block which
      contains pointers, and in that sense is a pointer to pointers.  Sometimes
      such variables use a 'pp' prefix to convey that idea.
    
      In a sense this is a silly app because the four strings are already satis-
      factorily stored in pNums[] below.  But that storage is in static program
      memory, and the purpose here is to show how a program can dynamically acquire
      storage for numbers of objects not known until runtime.
    */
    
    #include <memory.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    int main()
    {
     const char* pNums[]={"Zero","One","Two","Three"}; // Allocate in static memory some sample data
     size_t iNumStrs=sizeof(pNums)/sizeof(pNums[0]);   // How many objects?
     char** pMem=NULL;                                 // Declare Pointer to pointer buffer
     size_t i;
    
     pMem=(char**)malloc(sizeof(char*)*iNumStrs);      // Allocate buffer to hold four pointers
     printf("iNumStrs = %u\n",iNumStrs);               // Output number of pointers buffer will hold
     printf("pMem     = %u\n\n",(unsigned)pMem);       // Output address of memory block
     if(pMem)                                          // Test if allocation was successful
     {
        memset(pMem,0,iNumStrs*sizeof(void*));         // Zero out memory
        printf("&pMem[i]\tpMem[i]\t\tpMem[i]\n");
        printf("=======================================\n");
        for(i=0; i<iNumStrs; i++)
        {
            pMem[i]=(char*)malloc(strlen(pNums[i])+sizeof(char));  // Allocate memory from heap for each string
            if(pMem[i])                                            // Test memory
            {
               strcpy(pMem[i],pNums[i]);                           // Copy string to allocated memory
               printf("%u\t\t%u\t\t%s\n",(unsigned)&pMem[i],(unsigned)pMem[i],pMem[i]);
            }
        }
        for(i=0; i<iNumStrs; i++)
            free(pMem[i]);                             // Free string pointers held in memory block
        free(pMem);                                    // Free underlying memory block
     }
     getchar();
    
     return 0;
    }
    
    #if 0
    32 bit output ...
    
    iNumStrs = 4
    pMem     = 4072616
    
    &pMem[i]        pMem[i]         pMem[i]
    =======================================
    4072616         4072496         Zero
    4072620         4072640         One
    4072624         4072656         Two
    4072628         4072672         Three
    
    #endif
    
    
    #if 0
    64 bit output ...
    iNumStrs = 4
    pMem     = 3306864
    
    &pMem[i]        pMem[i]         pMem[i]
    =======================================
    3306864         8419008         Zero
    3306872         8419040         One
    3306880         8419072         Two
    3306888         8419104         Three
    
    #endif
    This same idea or design pattern comes up in many instances. For example, it is the foundational idea behind Microsoft's Component Object Model, which underlies a great deal of Window's functionality. Its also the foundational idea behind the virtual function tables C++ compilers create to implement classes.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    A few suggestions concerning the code from post #8:
    • Remove the #include <memory.h>. <memory.h> is non-standard; malloc and free are declared <stdlib.h>, memset is declared in <string.h>, and both these standard headers were already included.
    • Instead of:
      Code:
      pMem=(char**)malloc(sizeof(char*)*iNumStrs);
      Consider:
      Code:
      pMem = malloc(sizeof(pMem[0]) * iNumStrs);
      The reason is that the cast is unnecessary unless you need the code to be compilable as C++, and yet it can as an edge case hide the mistake of failing to #include <stdlib.h> by silencing the resulting warning. Using sizeof(pMem[0]) instead of sizeof(char*) tends to be better defensive programming: the reader does not need to check that pMem is a pointer to char*.
    • On the same note as the previous suggestion, instead of:
      Code:
      memset(pMem,0,iNumStrs*sizeof(void*));
      Consider:
      Code:
      memset(pMem, 0, iNumStrs * sizeof(pMem[0]));
      That said, you might as well have written:
      Code:
      pMem = calloc(iNumStrs, sizeof(pMem[0]));
      and dispensed with the memset. Personally, I feel this zeroing of memory is unnecessary here.
    • sizeof(char) == 1 is always true, so instead of:
      Code:
      strlen(pNums[i])+sizeof(char)
      one might as well write:
      Code:
      strlen(pNums[i]) + 1
      After all, the use of strlen(pNums[i]) without multiplying by sizeof(char) already relies on sizeof(char) == 1.
    • A size_t is not necessarily equivalent to unsigned int, so a compiler might warn when using printf with %u to print a size_t. This warning can be easily silenced with a cast of the size_t to unsigned int, but if you are compiling with respect to C99 or later a better solution would be to use %zu instead of %u.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    Like some of you are saying, i'm sure theres a simpler way to do it, however the assignment im doing it for require some things such as the deck being a dynamic array:

    Implementation requirements

    •A playing card is of the data type struct (called card), having a colour (♠, ♣, ♥, ♦,)and a value (Ace, 2, 3, . . ., 10, Knight, Queen andh King).

    • The deck of cards that is to be used has 52 unique playing cards and is stored in adynamically allocated array.

    • You must structure your solution so that there are functions to solve partial problems. There should be a separate function for each of the following points:

    – creates your array and fills it with unique cards in any sort order. Use thefollowing function prototype: struct card* createDeck();

    – takes a struct card-array and randomises the order of the deck.

    – calculates the sum of the cards passed to the function.

    The arguments should be a struct card-array and an int representing the size of the array.


    Some guidance would be great.

  11. #11
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Finoli View Post
    A playing card is of the data type struct (called card), having a colour (♠, ♣, ♥, ♦,)and a value (Ace, 2, 3, . . ., 10, Knight, Queen andh King).
    So,
    Code:
    struct card {
        unsigned char  colour; /* 0=♠, 1=♣, 2=♦, 3=♥ */
        unsigned char  value;  /* 1=ace, .., 11=knight, 12=queen, 13=king */
    };
    Quote Originally Posted by Finoli View Post
    The deck of cards that is to be used has 52 unique playing cards and is stored in adynamically allocated array.
    struct card* createDeck();
    That means you do not use a separate deck structure. To create a deck, something like
    Code:
    /* Return an array of 52 cards.
    */
    struct card *createDeck(size_t *const countptr)
    {
        const size_t  count = 52;
        struct card *deck;
    
        /* Allocate new deck of 'count' cards. */
        deck = malloc(count * sizeof deck[0]);
        if (!deck) {
            fprintf(stderr, "createDeck(): Out of memory!\n");
            exit(EXIT_FAILURE);
        }
    
        /* Update the count, if parent supplied a pointer to one. */
        if (countptr != NULL)
            *countptr = count;
    
        /*
         * TODO: initialize deck[0] to deck[count-1].
        */
    
        return deck;
    }
    Quote Originally Posted by Finoli View Post
    takes a struct card-array and randomises the order of the deck. The arguments should be a struct card-array and an int representing the size of the array.
    That's straightforward:
    Code:
    void shuffleDeck(struct card *const deck, const size_t count);
    The consts above just indicate that the function is not going to modify the variables deck or count. (It just modifies the data pointed to by deck, by modifying deck[0] to deck[count-1], inclusive.)

    Quote Originally Posted by Finoli View Post
    calculates the sum of the cards passed to the function. The arguments should be a struct card-array and an int representing the size of the array.
    Perhaps
    Code:
    unsigned int sumDeck(const struct card *const deck, const size_t count);
    When deciphering pointer types in C, it is always useful to consider it a sentence, separated by asterisks '*' (which you read as 'pointer to'). Start with the variable name on the right, followed by 'is a', followed by the rightmost part, then advancing part by part to left.

    For example, const char **const foo means "foo is a const pointer to pointer to const char(s)". That is, foo is constant (immutable); the pointer it points to (*foo or foo[0]) is not constant and you can modify it; and that pointer points to an immutable string (an array of const chars, or a string literal). For example, *foo = "Hello!"; would be okay, but foo = anything; is not, neither is foo[0][0] = anything;.

  12. #12
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    Thanks alot for your reply! Just a couple questions.

    Code:
    struct card *createDeck(size_t *constcountptr){
        const size_t  count = 52;
        struct card *deck;
    
        /* Allocate new deck of 'count' cards. */
        deck = malloc(count * sizeof deck[0]);
        if (!deck) {
            fprintf(stderr, "createDeck(): Out of memory!\n");
            exit(EXIT_FAILURE);
        }
    
        /* Update the count, if parent supplied a pointer to one. */
        if (countptr != NULL)
            *countptr = count;
    
        /*
         * TODO: initialize deck[0] to deck[count-1].
        */
    
        return deck;
    }
    Why is there a pointer-operator next to createDeck in
    struct card *createDeck(size_t *constcountptr) ? Why is it needed?
    Also, why does the function need arguments at all?

  13. #13
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    (When you paste code, paste it as text, without formatting. The code you pasted looks weird, because it's formatted differently than this board does. The board will automatically apply colors to the code between [CODE][/CODE] tags.)

    Quote Originally Posted by Finoli View Post
    Why is there a pointer-operator next to createDeck instruct card *createDeck(size_t *const countptr)? Why is it needed?
    Also, why does the function need arguments at all?
    It is not really needed. Let me explain.

    Whenever you have a function that returns a dynamically allocated array, you often (but not always) want to know its length, too. We can cater to that possibility by using a parameter that is a pointer to a size. If the caller supplies NULL, then the function knows that the caller is not interested in the size. If the caller supplies a non-NULL pointer, it points to where the caller wants the function to store the size.

    Do you have to do it that way? No. Would I do it that way? I don't know for sure, it depends on what kind of card games the deck is supposed to support -- some games have additional jokers, others use multiple decks. It might be better to instead have the caller specify the count, as in
    struct card *createDeck(const size_t count);
    If you only ever return 52-card decks, then not taking any parameters at all is okay,
    struct card *createDeck(void);

    Thinking about it, or more precisely, thinking about how do you envision the code to use the function, is the important part. You can even change it later if you change your mind, as long as you change all calls to the function, too.

    Wondering about this is a good sign.

  14. #14
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    I tried making something sort of based on Nominal Animal's code.

    Here's what I got:

    Code:
    #include <stdlib.h>#include <stdio.h>
    
    
    struct card {
        unsigned char suit;
        int value;
    };
    struct card *makeCard(int suit, int value, struct card *deckPtr) {
        struct card *tempCard;
        tempCard->suit = suit;
        tempCard->value = value;
    
    
        return tempCard;
    }
    
    
    struct card *createDeck()
    {
        const size_t  count = 52;
        struct card *deck;
    
    
        /* Allocate new deck of 'count' cards. */
        deck = malloc(count * sizeof deck[0]);
        if (!deck) {
            fprintf(stderr, "createDeck(): Out of memory!\n");
            exit(EXIT_FAILURE);
        }
        int i=0;
        struct card *deckArrayPtr = deck;
        for (int suit = 0; suit < 4; suit++) {
            for (int value = 0; value < 13; value++) {
                deck[i] = makeCard(suit, value, deckArrayPtr);
                    i++;
            }
        }
        return deck;
    }
    
    
    int main() {
    
    
        struct card *deckAr = createDeck();
    
    
        printf("%d", deckAr[1].value);
        
        return 0;
    }
    Now I get a couple errors at line 31:

    Error C2440 '=': cannot convert from 'card *' to 'card'
    and
    a value of type "struct card *" cannot be assigned to an entity of type "struct card"

    While I sort of understand what they errors imply i can't seem to figure out where the problem lies.

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Well when I compiled it I got errors on a different line, but it's like the problem you are talking about. I did have to fix some of your header #includes so that might have been the reason it's slightly different.

    Code:
    gcc -Wall --std=c99 -pedantic -g -o sandbox sandbox.c
    sandbox.c: In function 'createDeck':
    sandbox.c:35:21: error: incompatible types when assigning to type 'struct card' from type 'struct card *'
                 deck[i] = makeCard(suit, value, deckArrayPtr);
                         ^
    The easiest fix is to change what makeCard returns. It can't be a pointer anymore.
    Code:
    struct card makeCard(int suit, int value) {
    
        struct card tempCard;
    
        tempCard.suit = suit;
    
        tempCard.value = value;
    
     
    
     
    
        return tempCard;
    
    }
    It's probably for the best, since you weren't allocating the pointer that you were going to return, anyway. You also aren't using the 3rd argument, so I removed it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Trouble understanding Malloc, Calloc, and Realloc
    By matthayzon89 in forum C Programming
    Replies: 18
    Last Post: 10-19-2010, 12:20 AM
  2. help with structs and malloc!
    By coni in forum C Programming
    Replies: 20
    Last Post: 09-14-2009, 05:38 PM
  3. Malloc/and structs plz help
    By dezz101 in forum C Programming
    Replies: 1
    Last Post: 09-11-2008, 07:44 PM
  4. Help understanding typedef structs
    By difficult.name in forum C Programming
    Replies: 3
    Last Post: 09-22-2004, 12:43 AM
  5. Trouble understanding malloc() syntax
    By Sereby in forum C Programming
    Replies: 21
    Last Post: 07-28-2004, 10:19 AM

Tags for this Thread