开发者

Referencing a pointer to a struct that contains a pointer to a pointer to a struct

开发者 https://www.devze.com 2023-04-13 06:05 出处:网络
I\'m having a hard time referencing the memory inside the struct, I\'m not sure that my syntax is correct (although considering other posts I think I\'m fine).

I'm having a hard time referencing the memory inside the struct, I'm not sure that my syntax is correct (although considering other posts I think I'm fine). The code crashes in Run-time. As far as I'm aware I've allocated the momory needed (52 cards - line 66) but I'm not sure what casting to apply. I just need that little push and guidance, thanks alot !

#include <stdio.h>

#define DECK_SIZE (52)

/* the enum suite definition */
enum suite {
    diamond = 1,
    club,
    heart,
    spade
};

/* the card definition */
struct card {
    int number;
    enum suite type;
};

/* the deck definition */
struct deck {
    struct card ** cards;
    int numCards;
};

/* **
 * Name: addCard(deck *myDeck);
 * Purpose: Add a card to the deck
 ** */
void addCard(struct deck * myDeck)
{
    int number,suiteType;
    printf("Please enter card number: \n");
    scanf("%d",&number);
    printf("Please enter suite type: \n");
    scanf("%d",&suiteType);
    /* increase myDeck->numCards by one */
    myDeck->numCards += 1;
    /* reallocate the block and increase the size by one */
    *(myDeck->cards) = (struct card*) realloc ( *(myDeck->cards), sizeof(struct card) * myDeck->numCards);
    if ( NULL == *(myDeck->cards) ) {
        printf("realloc failed - exiting..\n");
        free( *(myDeck->cards));        
        return;
    }
    /* put the data */
    myDeck->cards[myDeck-&开发者_如何学Gogt;numCards-1]->number = number;
    myDeck->cards[myDeck->numCards-1]->type = suiteType;
}

/***
 * Name: initializeDeck();
 * Puspose: create a deck memory block and fill it
 ***/
struct deck * initializeDeck()
 {
    struct deck * myDeck;
    int num,suite,i;
    /* allocate memory for a deck */
    myDeck = (struct deck*) malloc ( sizeof(struct deck) );
    if (NULL == myDeck) {
        printf("Failed to allocate a deck, exiting..\n");
        return 0;
    }
    /* allocte 52 cards */
    myDeck->numCards = DECK_SIZE;
    myDeck->cards = (struct card**) malloc ( sizeof(struct card) * myDeck->numCards );
    if (NULL == *(myDeck->cards)) {
        printf("Failed to allocate 52 cards, exiting..\n");
        free(myDeck);
        return 0;
    }
    /* fill the deck */
    num = 1;
    suite=1;
    for (i = 0; i<DECK_SIZE; i++) {
        myDeck->cards[i]->number = num;
        myDeck->cards[i]->type = suite;
        num++;
        if (num > 13) {
            num = 1;
            suite++;
        }
    }
    return myDeck;
 }

int main()
{
    struct deck * myDeck;
    myDeck = initializeDeck();
    addCard(myDeck);
    return 0;
}


On the first glance I see two things (which might not solve the root cause, but actually could help in writing more save code ;-))

1.1 If initialising fails you return NULL, but you do not test the result of initializeDeck() but call addCard even if myDeck is NULL. So in case of an error during initialisation addCard causes a crash when dereferencing myDeck.

Either do like follows in main():

[...]
if (myDeck)
  addCard(myDeck);
[...]

or and even better and do like follows in addCard:

void addCard(struct deck * myDeck)
{
  if (!myDeck) {
    printf("invalid input\n");
    return;
  }
  [...]

1.2 malloc() returns NULL on failure, so test the result and do not dereference it:

[...]
myDeck->cards = (struct card**) malloc ( sizeof(struct card) * myDeck->numCards );
if (NULL == myDeck->cards) {
    printf("Failed to allocate 52 cards, exiting..\n");
[...]

Looking closer one realises you are obviously not sure how to arrange your data... ;-)

This line

myDeck->cards = (struct card**) malloc ( sizeof(struct card) * myDeck->numCards );

should allocate an array of pointers which's entries then in turn for each card should get memory assigend.

So there are two mistakes:

2.1 You assign to much memory to the pointer referencing the array of pointers to cards.

2.2 You are missing to assign the memory for the cards themselfs.

To fix 2.1 do change the line above into:

 myDeck->cards = (struct card**) malloc ( sizeof(struct card *) * myDeck->numCards );

To fix 2.2 do add the following to the loop assigning the cards' values.

  [...]
  for (i = 0; i<DECK_SIZE; i++) {
    myDeck->cards[i] = malloc(sizeof(struct card));
    /* adding error checking here is left as an exercise ... */
    myDeck->cards[i]->number = num;
    [...]

Adding those two fixes gets you further ... ;-)

Hint: The same two mistakes you did when allocating the deck (2.1 and 2.2) you do in the code adding a card (addCard()).

Btw: Casting the result of malloc() seems unnecessary to me, as malloc() return void * which is compatible to any pointer.

Anyhow type casting in general is not good idea as it keeps the compiler from pointing you to something which might be not the way it should be.


You allocate an array containing pointers to cards, but not the cards themselves.


This call allocates a single block of myDeck->numCards cards:

malloc ( sizeof(struct card) * myDeck->numCards );

...but a struct card ** is not the appropriate variable to hold a pointer to such a block. You should use just a struct card * for this member, and then use . rather than -> to access each member of this array:

myDeck->cards[i].number = num;
myDeck->cards[i].type = suite;

The rule to use is that a type * points at a (block of) types. So a struct card * is for pointing at a (block of) struct cards, and a struct card ** points at a (block of) struct card *s.

If you want to use a struct card ** member in your struct, you need to first allocate a block of struct card *s for it to point at:

myDeck->cards = malloc (sizeof(struct card *) * myDeck->numCards);
if (NULL == myDeck->cards) {
    fprintf(stderr, "Failed to allocate %d card pointers, exiting..\n", myDeck->numCards);

Now you can allocate the cards themselves, putting the pointers to the cards in the array of pointers allocated earlier. The simplest way to do this is one allocation per card:

for (i = 0; i < myDeck->numCards; i++)
    myDeck->cards[i] = malloc(sizeof(struct card));

Your reallocation should then look like:

struct card **new_block;

myDeck->numCards += 1;
/* reallocate the block of pointers and increase the size by one */
new_block = realloc (myDeck->cards, sizeof(struct card *) * myDeck->numCards);
if (NULL == new_block) {
    fprintf(stderr, "realloc failed - exiting..\n");
    return;
}
myDeck->cards = new_block;
/* Allocate the new card */
myDeck->cards[myDeck->numCards - 1] = malloc(sizeof(struct card));
if (myDeck->cards[myDeck->numCards - 1] == NULL) {
    fprintf(stderr, "failed to allocate card\n");
    myDeck->numCards--;
    return;
}
/* put the data */
myDeck->cards[myDeck->numCards - 1]->number = number;
myDeck->cards[myDeck->numCards - 1]->type = suiteType;
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号