#c #pointers #nested
#c #указатели #вложенный
Вопрос:
Мне трудно ссылаться на память внутри структуры, я не уверен, что мой синтаксис правильный (хотя, учитывая другие сообщения, я думаю, что я в порядке). Во время выполнения происходит сбой кода. Насколько мне известно, я выделил необходимую momory (52 карточки — строка 66), но я не уверен, какое приведение применить. Мне просто нужен этот небольшой толчок и руководство, большое спасибо!
#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",amp;number);
printf("Please enter suite type: n");
scanf("%d",amp;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->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;
}
Ответ №1:
На первый взгляд я вижу две вещи (которые могут не решить основную причину, но на самом деле могут помочь в написании большего количества кода сохранения ;-))
1.1 Если инициализация завершается неудачно, вы возвращаете значение NULL , но вы не проверяете результат initializeDeck()
, а вызываете addCard
, даже если myDeck
значение равно NULL . Таким образом, в случае ошибки во время инициализации addCard
происходит сбой при разыменовании myDeck
.
Либо выполните следующие действия в main()
:
[...]
if (myDeck)
addCard(myDeck);
[...]
или и даже лучше, и выполните следующие действия в addCard
:
void addCard(struct deck * myDeck)
{
if (!myDeck) {
printf("invalid inputn");
return;
}
[...]
1.2 malloc()
возвращает NULL при сбое, поэтому проверьте результат и не разыменовывайте его:
[...]
myDeck->cards = (struct card**) malloc ( sizeof(struct card) * myDeck->numCards );
if (NULL == myDeck->cards) {
printf("Failed to allocate 52 cards, exiting..n");
[...]
При ближайшем рассмотрении становится понятно, что вы, очевидно, не уверены, как упорядочить свои данные … 😉
Эта строка
myDeck->cards = (struct card**) malloc ( sizeof(struct card) * myDeck->numCards );
следует выделить массив указателей, записи которых затем, в свою очередь, для каждой карты должны получить назначение памяти.
Итак, есть две ошибки:
2.1 Вы назначаете много памяти указателю, ссылающемуся на массив указателей на карточки.
2.2 Вам не хватает, чтобы назначить память для самих карт.
Чтобы исправить 2.1, измените строку выше на:
myDeck->cards = (struct card**) malloc ( sizeof(struct card *) * myDeck->numCards );
Чтобы исправить 2.2, добавьте следующее в цикл присвоения значений карт.
[...]
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;
[...]
Добавление этих двух исправлений продвинет вас дальше … 😉
Подсказка: те же две ошибки, которые вы допустили при распределении колоды (2.1 и 2.2), вы делаете в коде добавления карты ( addCard()
).
Кстати: приведение результата malloc()
мне кажется ненужным, поскольку malloc()
return void *
совместим с любым указателем.
В любом случае приведение типов в целом не является хорошей идеей, поскольку оно не позволяет компилятору указывать вам на то, что может быть не так, как должно быть.
Комментарии:
1. большое вам спасибо за подробное объяснение! мне очень помогло!
Ответ №2:
Вы выделяете массив, содержащий указатели на карточки, но не сами карточки.
Ответ №3:
Этот вызов выделяет один блок myDeck->numCards
карточек:
malloc ( sizeof(struct card) * myDeck->numCards );
…но a struct card **
не является подходящей переменной для хранения указателя на такой блок. Вы должны использовать только a struct card *
для этого элемента, а затем использовать .
, а не ->
для доступа к каждому элементу этого массива:
myDeck->cards[i].number = num;
myDeck->cards[i].type = suite;
Правило, которое нужно использовать, заключается в том, что a type *
указывает на (блок) type
s . Таким образом, a struct card *
указывает на (блок) struct card
s, а a struct card **
указывает на (блок) struct card *
s .
Если вы хотите использовать struct card **
элемент в своей структуре, вам нужно сначала выделить блок struct card *
s, чтобы он указывал на:
myDeck->cards = malloc (sizeof(struct card *) * myDeck->numCards);
if (NULL == myDeck->cards) {
fprintf(stderr, "Failed to allocate %d card pointers, exiting..n", myDeck->numCards);
Теперь вы можете распределять сами карты, помещая указатели на карты в массив указателей, выделенных ранее. Самый простой способ сделать это — одно выделение на карту:
for (i = 0; i < myDeck->numCards; i )
myDeck->cards[i] = malloc(sizeof(struct card));
Затем ваше перераспределение должно выглядеть так:
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 cardn");
myDeck->numCards--;
return;
}
/* put the data */
myDeck->cards[myDeck->numCards - 1]->number = number;
myDeck->cards[myDeck->numCards - 1]->type = suiteType;
Комментарии:
1. хорошо, но допустим, что я «вынужден» использовать ‘struct card **’ (следовательно, указатель на указатель). Вы бы реализовали это иначе, чем то, что я реализовал выше?
2. @shluvme: Да. Если вы используете a
struct card **
, то у вас фактически есть массив указателей на карточки, а не массив карточек. Это означает, что вы должны выделить блок указателей и выделить сами карточки — я обновил свой ответ, чтобы показать это.3. большое вам спасибо! действительно, это то, что я в итоге сделал, и оно выполнило свою работу 🙂