【问题标题】:C: accessing members of struct in a functionC:在函数中访问结构的成员
【发布时间】:2013-05-14 10:34:09
【问题描述】:

我试图在我的函数 print_shoe 中使用结构成员 'size',但我的 for 循环没有运行。但是,如果我在 for 循环中用 int 替换 'c->size',它运行得很好

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DECK_SIZE 52
#define NUM_FACES 13
#define NUM_SUITS 4
#define LENGTH_FACES 6
#define LENGTH_SUITS 9

typedef struct cards {
  char suits[NUM_SUITS][LENGTH_SUITS];
  char faces[NUM_FACES][NUM_FACES];
  int suit, face, card, value, size;
  int *values[NUM_FACES];
} cards;

char buf[101];
void print_shoe();
void init_decks();
int rand_int();
void shuffle();

int main(void) {

  srand( time(NULL) );

  int decks_input = 0;    
  int numberOfDecks = 1;

  do {
    printf("\nEnter number of decks to be used in the game (1-8):\n\n");
    if (fgets(buf, sizeof(buf), stdin) != NULL)
      if (sscanf (buf, "%d", &decks_input))
        numberOfDecks = decks_input;
     } while (numberOfDecks < 1 || numberOfDecks > 8);

  cards *shoe = malloc(sizeof(cards) * numberOfDecks * DECK_SIZE);
  shoe->size = numberOfDecks * DECK_SIZE;

  shuffle(shoe);
  print_shoe(shoe);

  free(shoe);

  return 0;
}

void print_shoe(cards *c) {
  int i;
  for (i = 0; i < c->size; i++) {
    printf("card #%d = %s of %s\n", i+1, c->faces[c[i].face], c->suits[c[i].suit]);
  }
}

void init_decks(cards *c) {
  int i;
  for (i = 0; i < c->size; i++) {
    c[i].card = i;
    c[i].suit = c[i].card % NUM_SUITS;
    c[i].face = c[i].card % NUM_FACES;
  }  
}

void shuffle(cards *c) {
  init_decks(c);

  int i, j;
  cards tmp;
  for (i = c->size - 1; i > 0 ; i--) {
    j = rand_int(i + 1);
    tmp = c[j];
    c[j] = c[i];
    c[i] = tmp;
  }
}

int rand_int(int n) {
  int limit = RAND_MAX - RAND_MAX % n;
  int rnd;

  do {
    rnd = rand();
     } while (rnd >= limit);
  return rnd % n;
}

编辑:问题已被广泛更新,以回应需要更多澄清的 cmets

【问题讨论】:

  • 您的代码无法编译。 1. 将print_shoe 放在main 之前 2. (cards *)malloc(...)。更改这些后,它在我的机器上运行良好。
  • @gongzhitaao:演员阵容是不必要的,也是个坏主意。只要确保你有#include &lt;stdlib.h&gt;,从void*cards* 的转换将隐式完成。
  • 您尚未定义bufDECK_SIZE,并且缺少&lt;stdio.h&gt;&lt;stdlib.h&gt; 所需的#include 指令。你说你的函数“无法访问”结构成员。这意味着什么?当你尝试时会发生什么?您是否收到编译时错误消息?如果是这样,请向我们展示。向我们展示显示问题的complete sample program,并告诉我们问题所在。
  • printf("card #%d = %s of %s\n", i+1, c-&gt;faces[c[i].face], c-&gt;suits[c[i].suit]);你指的是没有初始化的部分。
  • 调试器很容易显示这一点:您初始化了shoe 指向的数组中第一个cardssize,而另一个cards 的@ 值未初始化987654339@。当您随机播放时,未初始化的cards 之一成为shoe 中的第一个条目,并且您正在使用未初始化的变量。 size 不属于 cards 结构。

标签: c struct


【解决方案1】:

在修改后的代码中,你有:

cards *shoe = malloc(sizeof(cards) * numberOfDecks * DECK_SIZE);
shoe->size = numberOfDecks * DECK_SIZE;

// You probably need init_decks(shoe); here!!!

shuffle(shoe);
print_shoe(shoe);

print_shoe() 中的代码只是在打印,但除了大小之外,您还没有初始化来自malloc() 的数据,所以您打印的是垃圾。 malloc() 返回的数据是未初始化的,必须在读取前进行初始化。我打字的时候问题变了;你还没有像你需要的那样打电话给init_decks(shoe);


这不是它不起作用的原因——我不确定现在的问题是什么——但这几乎值得评论。你有:

void shuffle(cards *c) {
  init_decks(c);

  int i, j;
  cards tmp;
  for (i = c->size - 1; i > 0 ; i--) {
    j = rand_int(i + 1);
    tmp = c[j];
    c[j] = c[i];
    c[i] = tmp;
  }
}

如果您要使用 C99 技术以最小范围声明变量,那么您应该编写:

void shuffle(cards *c) {
  init_decks(c);
  for (int i = c->size - 1; i > 0; i--) {
    int j = rand_int(i + 1);
    cards tmp = c[j];
    c[j] = c[i];
    c[i] = tmp;
  }
}

(如果它是这样写的,我就不会错过给init_decks() 的电话了。)


正如评论中所述,您的cards 结构相当头重脚轻。您(为每张卡片)分配足够的空间来存储它可能拥有的等级和套装。这个真的没必要。

此代码将DeckCard 分开。它在Deck结构中使用了一个灵活的数组成员来容纳卡片,这很方便。您可能更喜欢在那里使用常规指针,在这种情况下,您需要一对内存分配和一个函数deck_free() 来释放deck_alloc() 分配的内存。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define NUM_FACES 13
#define NUM_SUITS 4
#define DECK_SIZE (NUM_FACES * NUM_SUITS)
#define LENGTH_FACES 6
#define LENGTH_SUITS 9

static const char suits[NUM_SUITS][LENGTH_SUITS] =
{
    "Clubs",
    "Diamonds",
    "Hearts",
    "Spades"
};
static const char faces[NUM_FACES][NUM_FACES] =
{
    "Ace",
    "Deuce",
    "Three",
    "Four",
    "Five",
    "Six",
    "Seven",
    "Eight",
    "Nine",
    "Ten",
    "Jack",
    "Queen",
    "King",
};

typedef struct Card
{
  int suit;
  int face;
  int card;
} Card;

typedef struct Deck
{
  int size;
  Card cards[];     // Flexible array member
} Deck;

void print_shoe(const Deck *d);
void init_decks(Deck *d);
int rand_int(int n);
void shuffle(Deck *d);
static Deck *deck_alloc(int numberOfDecks);

int main(void)
{
    srand( time(NULL) );
    int numberOfDecks = 1;

    do
    {
        char buf[101];
        printf("\nEnter number of decks to be used in the game (1-8):\n\n");
        if (fgets(buf, sizeof(buf), stdin) != NULL)
        {
            int decks_input;    
            if (sscanf (buf, "%d", &decks_input))
                numberOfDecks = decks_input;
        }
    } while (numberOfDecks < 1 || numberOfDecks > 8);

    Deck *shoe = deck_alloc(numberOfDecks);
    shuffle(shoe);
    print_shoe(shoe);
    free(shoe);

    return 0;
}

static Deck *deck_alloc(int numberOfDecks)
{
    Deck *shoe  = malloc(sizeof(Deck) + (sizeof(Card) * numberOfDecks * DECK_SIZE));
    if (shoe == 0)
    {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    shoe->size = numberOfDecks * DECK_SIZE;
    return shoe;
}

void print_shoe(const Deck *d)
{
    for (int i = 0; i < d->size; i++)
        printf("card #%d = %s of %s\n", i+1, faces[d->cards[i].face], suits[d->cards[i].suit]);
}

void init_decks(Deck *d)
{
    for (int i = 0; i < d->size; i++)
    {
        d->cards[i].card = i;
        d->cards[i].suit = d->cards[i].card % NUM_SUITS;
        d->cards[i].face = d->cards[i].card % NUM_FACES;
    }  
}

void shuffle(Deck *d)
{
    init_decks(d);
    for (int i = d->size - 1; i > 0 ; i--)
    {
        int j = rand_int(i + 1);
        Card tmp = d->cards[j];
        d->cards[j] = d->cards[i];
        d->cards[i] = tmp;
    }
}

int rand_int(int n)
{
    int limit = RAND_MAX - RAND_MAX % n;
    int rnd;

    do
    {
        rnd = rand();
    } while (rnd >= limit);
    return rnd % n;
}

样本输出:

$ ./cards

Enter number of decks to be used in the game (1-8):

1
card #1 = Eight of Clubs
card #2 = Jack of Clubs
card #3 = Deuce of Diamonds
card #4 = Jack of Hearts
card #5 = Queen of Clubs
card #6 = Four of Hearts
card #7 = Six of Spades
card #8 = King of Hearts
card #9 = Five of Spades
card #10 = King of Clubs
card #11 = Deuce of Clubs
card #12 = King of Spades
card #13 = Four of Spades
card #14 = Nine of Diamonds
card #15 = Five of Hearts
card #16 = Deuce of Spades
card #17 = Ten of Clubs
card #18 = Five of Diamonds
card #19 = Ten of Spades
card #20 = Three of Spades
card #21 = Nine of Hearts
card #22 = Six of Clubs
card #23 = Ace of Clubs
card #24 = Three of Clubs
card #25 = Queen of Hearts
card #26 = Jack of Diamonds
card #27 = Nine of Clubs
card #28 = Four of Clubs
card #29 = Seven of Spades
card #30 = Ace of Diamonds
card #31 = Six of Diamonds
card #32 = Three of Hearts
card #33 = Queen of Diamonds
card #34 = Ten of Hearts
card #35 = Ten of Diamonds
card #36 = Seven of Diamonds
card #37 = Seven of Clubs
card #38 = Deuce of Hearts
card #39 = Ace of Hearts
card #40 = Jack of Spades
card #41 = Eight of Diamonds
card #42 = Eight of Spades
card #43 = Ace of Spades
card #44 = Three of Diamonds
card #45 = Queen of Spades
card #46 = Five of Clubs
card #47 = Four of Diamonds
card #48 = King of Diamonds
card #49 = Nine of Spades
card #50 = Eight of Hearts
card #51 = Six of Hearts
card #52 = Seven of Hearts
$

【讨论】:

  • init_decks(shoe) 在 shuffle 中被调用(即使这可能是不好的做法)。我对编辑表示歉意,并尝试尽快完成 - 我真的不想浪费任何人的时间
  • 不知道你说的初始化malloc()返回的数据是什么意思
  • 我错过了shuffle() 中对init_decks() 的呼叫,当我开始接听时,也没有对shuffle() 的呼叫。初始化数据意味着在您尝试从malloc() 返回的空间中读取任何内容之前,您先向其中写入一些内容。无法保证您在分配的空间中会得到零或任何其他值;它通常是字节的准随机混杂(但它不是随机过程的良好熵源)。
  • 你能举个例子吗?
  • 你的init_decks() 做了一些初始化—它写入cards 结构的某些元素(幸运的是,NUM_DECKS == NUM_FACES * NUM_SUITS)。但是,您的 cards 结构是多种描述的混合体。您有足够的存储空间在每个条目中存储一副完整的卡片名称,但您只有一个 face 和一个 card 和一个 suit。你需要清理结构。您还需要设置所有内容。初始化分配内存的标准方法是使用memset()(通常指定0作为字节值)或使用calloc()而不是malloc()
【解决方案2】:

直接解决问题并忽略这种方法的智慧,您的问题如下(Raymond Chen也提到过)。

  cards *shoe = malloc(sizeof(cards) * numberOfDecks * DECK_SIZE);

上面的行使鞋指向足够的内存来存储(numberOfDecks * DECK_SIZE)struct cards。结构体和成员都在此时单元化,这意味着shoe[i].size 可以是任何位序列。

shoe->size = numberOfDecks * DECK_SIZE;

这一行只查看第一个struct cards,并将其size 设置为(numberOfDecks * DECK_SIZE)。其余的struct cardssize 成员保持单元化。

shuffle 中,您对init_decks 的调用会初始化cardsuitface,但不会初始化size。当你稍后洗牌时,带有size 成员的卡片很有可能成为第一个。

因此,根据您当前的方法,如果您将此行添加到init_decks,以下内容应该会得到您想要的。

void init_decks(cards *c) {
      int i;
      int size = c->size;
      for (i = 0; i < c->size; i++) {
            c[i].size = size;
            c[i].card = i;
            c[i].suit = c[i].card % NUM_SUITS;
            c[i].face = c[i].card % NUM_FACES;
       }  
}

【讨论】:

    【解决方案3】:

    您已经声明了一个指针,但尚未将其初始化为指向的有效内存位置。

     ex *ex_p = malloc(sizeof(ex));
     ex_p->size = 10;
    

    【讨论】:

    • 不幸的是,我确实在我的代码中这样做了。你还能发现其他什么吗?好像循环甚至没有运行..但也没有给我任何错误。如果我只是将 for 循环中的 'ptr->size' 与值 '10' 交换,则效果很好
    • 如果你只有一次实例,那么迭代或使用 for 循环是没有意义的。你能发布你完整的实际代码吗?
    猜你喜欢
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 2016-11-14
    • 2010-09-17
    相关资源
    最近更新 更多