在C中扩展动态数组并且什么也得不回来

时间:2018-03-07 22:09:57

标签: c arrays malloc

C noob在这里。当main()全部存在时,我有一些代码工作正常,但是当我开始将它分解出去时,它就死了。我知道这很简单,我错过了一些关键元素,我只需要展示一次(我保证!)。所以这里:

在types.h中:

typedef struct {
  char *orig_str; // various ints snipped for clarity
} Card;

typedef struct {
  size_t num_cards;
  Card *cards;  // same here
} Deck;

在main.c中:

int main(int argc, char **argv) {
  Deck deck;
  // clipped the part opening input_fp, it's working fine
  read_deck(&deck, input_fp);
  for(int i = 0; i < deck.num_cards; i++) {
    fprintf("%s", deck.cards[i].orig_str);
  }
}

在input.c中,我之前在main中移动了代码:

void read_deck(Deck *deck, FILE *pfile) {
  Card *card = NULL;
  char line_buf[MAX_LINE_LEN];
  int line_len;

  while(TRUE) {
    if(read_line(line_buf, input_fp) == EOF) break;
    line_len = strlen(line_buf);

    /* make a new card and copy in the text */
    card = calloc(1, sizeof(Card));
    card->orig_str = calloc(1, line_len * sizeof(char));
    strcpy(card->orig_str, line_buf);

    /* calloc/realloc the deck and add this card to it */
    if(deck->num_cards == 0) {
      deck->num_cards++;
      deck->cards = calloc(1, sizeof(Card *));
    } else {
      deck->num_cards++;
      deck->cards = realloc(deck->cards, deck->num_cards*sizeof(Card *));
    }
    deck->cards[deck->num_cards - 1] = *card;
  }
}

当我在read_deck内的gdb中追踪时,一切似乎都很好,我可以:

 p deck->cards[0].orig_str = "CM TESTEX5"
 p deck->cards[1].orig_str = "CM YAGI TEST"
 p deck->cards[2].orig_str = "CM 78 SEGMENTS. SIGMA"

但是当循环完成并返回main时,[0]以外的大多数牌都不再有值:

p deck->cards[0].orig_str = "CM TESTEX5"
p deck->cards[1].orig_str = ""
p deck->cards[2].orig_str = ""

深入挖掘,我可以看到从非常不同的卡上显示的有效数据 - 卡24 orig_str看起来没问题,但它的数据来自卡30!下次我运行时,该数据在卡20中。

我认为问题在于我正在修改错误大小的内容,因此数组或字符串指针是错误的。但为什么只会在方法结束时发生?

好的,我做错了什么?

3 个答案:

答案 0 :(得分:1)

deck->cardsCards的数组,而不是Card *的数组,因此您的分配不正确。

calloc(1, sizeof(Card *));

仅为指针到卡分配空间,但是您需要Card对象的空间。改为

calloc(1, sizeof(Card));.

realloc

相同

但是,因为您已经在堆上分配了Card

card = calloc(1, sizeof(Card));

您可以将数组的类型更改为Card **,并将这些指针存储在数组中

deck->cards[deck->num_cards - 1] = card;

但我不认为你想这样做,所以你可能会忽视这一点。

您不需要在堆上分配临时Card。您可以将局部变量更改为:

Card card;

并完全取消card = calloc(1, sizeof(Card));。因为你有一个内存泄漏,因为你从来没有free他们,但这样你就不用担心了。

最后请注意,deck->cards[deck->num_cards - 1] = *card;执行浅拷贝。这可能是也可能不是问题。无法用简化代码说出来。

更新功能:

void read_deck(Deck *deck, FILE *pfile) {
  Card card;   // No longer a pointer
  char line_buf[MAX_LINE_LEN];
  int line_len;

  while(TRUE) {
    if(read_line(line_buf, input_fp) == EOF) break;
    line_len = strlen(line_buf);

    /* make a new card and copy in the text */
    // You weren't allocating space for the '\0' so +1 added
    card.orig_str = calloc(1, (line_len + 1) * sizeof(char));
    strcpy(card->orig_str, line_buf);

    /* calloc/realloc the deck and add this card to it */
    if(deck->num_cards == 0) {
      deck->num_cards++;
      deck->cards = calloc(1, sizeof(Card));
    } else {
      deck->num_cards++;
      deck->cards = realloc(deck->cards, deck->num_cards*sizeof(Card));
    }
    // Shallow copy temp object to array
    deck->cards[deck->num_cards - 1] = card;
  }
}

我还应该提一下,使用realloc指针调用NULL与调用malloc相同,这样您只需进行1次分配即可进一步简化。

答案 1 :(得分:0)

malloc不需要。 calloc很好,你实现它的方式也是如此。 Card初始化为多大?

card = calloc(1, sizeof(Card));

如果没有特定值,那么它可以在每次迭代时切断数据,这就是为什么只是通过它进行跟踪工作并且一切都可见但不是在你调用fprintf函数时。

答案 2 :(得分:0)

似乎以下行有逻辑错误:

if(deck->num_cards == 0) {
  deck->num_cards++;
  deck->cards = calloc(1, sizeof(Card *));
} else {
  deck->num_cards++;
  deck->cards = realloc(deck->cards, deck->num_cards*sizeof(Card *));
}

您很可能打算为calloc(1, sizeof(Card))realloc。如果sizeof(Card *) == sizeof(Card)您可能不会注意到任何问题,那么您的剪切示例确实如此,因为Card只包含指针成员。