【问题标题】:C method for moving structs between dynamic arrays用于在动态数组之间移动结构的 C 方法
【发布时间】:2014-12-29 06:04:12
【问题描述】:

我有一个 C 语言的纸牌游戏(我必须在 C 类项目中制作它)。我创建了一种将结构从一个动态数组移动到另一个的方法。不幸的是,该方法起初有效,但后来当我在程序中调用它时,它开始抛出 malloc() 错误。 Deck 是一个结构体,包含一个int size 和一个动态分配的Card *deck,而Card 是一个用于存放单张卡片的结构体。有什么我遗漏的东西,或者必须以其他方式定义吗?

void moveCard(Deck *src, Deck *dest, int n){
    Card *tmpCards = NULL;
    Card tmp = (*src).deck[n];                          // get card to be copied
    int newSize = dest->size + 1;                       //increase dest size by 1
    tmpCards = (Card *) malloc(sizeof(Card) * newSize); // allocate new memory area
    memmove(&(tmpCards[0]), &(dest->deck[0]), sizeof(Card) * (newSize - 1)); 
        // copy all the cards from old memory area to new area
    dest->deck = tmpCards;  // reassign old pointer to new memory area
    dest->size = newSize;   // reevaluate size
    dest->deck[newSize - 1] = tmp; // copy card to end of new area


    tmpCards = NULL; // empty out pointer (no functionality, just for easier reading)
    newSize = src->size; // reevaluate newSize 
    tmpCards = (Card *) malloc(sizeof(Card) * (newSize - 1));
                     // allocate smaller mem area by 1
    memmove(&(tmpCards[0]),&(src->deck[0]), sizeof(Card) * (n));
                     // copy all cards up to the n-th point 
    memmove(&(tmpCards[n]),&(src->deck[n+1]), sizeof(Card) * (newSize - n));
                     // copy all cards from the n+1 -th point

    src->size = newSize -1; // reevaluate size
    src->deck = tmpCards;     // reassign pointer

    // since all input parameters were pointers, no return is necessary
}

编辑:对我不释放内存这一事实的关注的人。原始代码中有 2 个免费命令(free(dest->deck)free(src->deck))。但只有其中一个有效。另一个出于某种奇怪的原因再次造成了内存损坏,所以我发现它更好,而不是把它们放在这个例子中。

【问题讨论】:

  • 第1点,请do not castmalloc()的返回值。第2点。你不能用realloc()吗?
  • 在分配tmpCards 之前,您不应该释放旧的dest->deck 吗?还是它还没有指向任何东西?
  • 如果您知道任何一副牌可能包含的最大卡片数量,而且这不是一个大得离谱的数字,您可以考虑使用固定大小的 deck 数组,其中 size 表示使用了多少,而不是每次移动卡时都不断重新分配内存……它可能会大大提高性能。
  • “另一个出于某种奇怪的原因再次造成了内存损坏” - 不, 造成了内存损坏,free() 只是提醒您注意这一事实。你需要解决这个问题。
  • malloc 中的错误可能是由之前执行的程序的完全不同部分的内存损坏引起的。如果您有缓冲区溢出并在分配的内存之外写入,您可能会破坏 malloc 系统的内部数据结构,并在很久以后发生崩溃。因此,这样的程序片段有时在调试时并没有多大用处。使用调试器或类似 valgrind 的工具来查找您的实际问题。

标签: c arrays dynamic struct


【解决方案1】:

我认为您的内存不足是因为您没有释放任何内存。你只是在分配新的内存。

void moveCard(Deck *src, Deck *dest, int n){
    Card *tmpCards = NULL;
    Card tmp = (*src).deck[n];                          // get card to be copied
    int newSize = dest->size + 1;                       //increase dest size by 1
    tmpCards = (Card *) malloc(sizeof(Card) * newSize); // allocate new memory area
    memmove(&(tmpCards[0]), &(dest->deck[0]), sizeof(Card) * (newSize - 1)); 
        // copy all the cards from old memory area to new area

    // **** CORRECTION ****
    // Free previously allocated memory for dest->deck
    free(dest->deck);

    dest->deck = tmpCards;  // reassign old pointer to new memory area
    dest->size = newSize;   // reevaluate size
    dest->deck[newSize - 1] = tmp; // copy card to end of new area


    tmpCards = NULL; // empty out pointer (no functionality, just for easier reading)
    newSize = src->size; // reevaluate newSize 
    tmpCards = (Card *) malloc(sizeof(Card) * (newSize - 1));
                     // allocate smaller mem area by 1
    memmove(&(tmpCards[0]),&(src->deck[0]), sizeof(Card) * (n));
                     // copy all cards up to the n-th point 
    memmove(&(tmpCards[n]),&(src->deck[n+1]), sizeof(Card) * (newSize - n));
                     // copy all cards from the n+1 -th point

    src->size = newSize -1; // reevaluate size

    // **** CORRECTION ****
    // Free previously allocated memory for src->deck
    free(src->deck);

    src->deck = tmpCards;     // reassign pointer

    // since all input parameters were pointers, no return is necessary
}

PS您应该使用memcpy 而不是memmove。如果源和目标重叠,memmove 是正确的函数。如果源和目标不重叠,memcpy 是正确的函数。

【讨论】:

  • 我会试试memcpy。谢谢你的建议。如果可行,那么我会突出显示您的答案
  • 即使区域重叠,使用 memmove 也没有问题。为了统一性和代码稳健性,甚至可以推荐它。
  • @ThomasPadron-McCarthy, memmove 将比memcpy 更昂贵,因为前者使用临时缓冲区首先从源复制数据,然后将其复制到目标。对于手头的问题,这可能是问题,也可能不是问题。
  • @RSahu:不,memmove 不使用临时缓冲区。它所要做的就是检查重叠,如果发现,根据重叠的类型从区域的顶部或底部开始复制。例如,请看这里:opensource.apple.com/source/ntp/ntp-13/ntp/libntp/memmove.c可以使用临时缓冲区,但它不是必需的,而且这是一种非常低效的方法。
  • @ThomasPadron-McCarthy,说得好。 memmove 没有必要使用临时缓冲区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-14
  • 2017-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-10
相关资源
最近更新 更多