【问题标题】:How to dynamically allocate memory without affecting other data allocated dynamically?如何动态分配内存而不影响其他动态分配的数据?
【发布时间】:2019-04-24 10:11:53
【问题描述】:

我正在使用 C 实现纸牌游戏,这是我的代码:

甲板.h:

#ifndef DECK_H
    #define DECK_H
    #define S_NUM 4
    #define V_NUM 12
    #define S_MAXLEN 9
    #define V_MAXLEN 6
    #define OFLEN 5

    typedef char deck_t
        [S_NUM * V_NUM]
            [S_MAXLEN + V_MAXLEN + OFLEN];
    
    typedef struct {
        deck_t *hand;
        deck_t *remaining_cards;
    } dealed_deck_t;
    
    deck_t *new_deck(void);
    void print_deck(const deck_t *);
    dealed_deck_t deal(const deck_t *, int);
    void free_deck(const deck_t *);
    
    static void deckcpy(const deck_t *const, deck_t *, int);
    
#endif

deck.c:

#include "deck.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

deck_t *new_deck() {
    int i, j, k;
    deck_t *cards = calloc(1, sizeof(deck_t));
    char suits[S_NUM][S_MAXLEN] = {
        "Spades", "Diamonds",
        "Hearts", "Clubs"
    };
    char values[V_NUM][V_MAXLEN] = {
        "Ace", "Two", "Three",
        "Four", "Five", "Six",
        "Seven", "Eight", "Nine",
        "Jack", "Queen", "King"
    };
    for (i = 0; i < S_NUM * V_NUM; ++i) {
        memset(*cards[i], 0, strlen(*cards[i]));
    }
    for (i = 0, j = 0; i < S_NUM; ++i) {
        for (k = 0; k < V_NUM; ++k, ++j) {
            strcat(*cards[j], values[k]);
            strcat(*cards[j], " of ");
            strcat(*cards[j], suits[i]);
        }
    }
    return cards;
}

void print_deck(const deck_t *deck) {
    for (int i = 0; i < S_NUM * V_NUM && strlen(*deck[i]); ++i) {
        printf("%s\n", *deck[i]);
    }
}

dealed_deck_t deal(const deck_t *deck, int handsize) {
    int i, j;
    dealed_deck_t dealed_deck;
    dealed_deck.hand = calloc(1, sizeof(deck_t));
    dealed_deck.remaining_cards = calloc(1, sizeof(deck_t));
    
    // print_deck(deck);
    
    return dealed_deck;
}

void free_deck(const deck_t *deck) {
    free((void *)deck);
}

static void deckcpy(const deck_t *const deck, deck_t *dest, int handsize) {
    for (int i = 0; i < handsize; ++i) {
        char temp[strlen(*deck[i])];
        for (int j = 0; j < strlen(*deck[i]); ++j) {
            temp[j] = (*deck[i])[j];
            temp[j] = '\0';
        }
        for (int j = 0; j < strlen(temp); ++j) {
            (*dest[i])[j] = temp[j];
            (*dest[i])[j] = '\0';
        }
    }
}

main.c:

#include "deck.h"

int main() {
    deck_t *cards = new_deck();
    deck_t *hand = deal(cards, 6).hand;
    // print_deck(cards);
    free_deck(cards);
    return 0;
}

问题是deal 函数中的deck.c。 当我为dealed_deck.handdealed_deck.remaining_cards 分配内存时,参数deck 指向的数据受到影响和改变,所以当我评论这两行时: dealed_deck.hand = calloc(1, sizeof(deck_t));dealed_deck.remaining_cards = calloc(1, sizeof(deck_t));,数据是一样的,我取消注释的时候数据有点变化。

我在这里使用calloc,因为当我使用malloc 时,dealed_deck.handdealed_deck.remaining_cards 指向的数据与deck 指向的数据相同,但是当我使用calloc 时,它们是随心所欲。

我需要一种分配内存的方法,而不会弄乱我之前分配的内存和数据,该怎么做?

我正在使用 MacOS 和 gcc 进行编译。 谢谢。

【问题讨论】:

  • 鉴于cardsdeck_t *,您认为cards[i] 是什么?您可能应该打开 all 编译器警告...
  • 我根本没有编译器警告,我是这样编译的:gcc main.c deck.c
  • 当我使用 -Wall 编译当前代码时,我得到的只是未使用的变量和未使用的函数
  • 整体方法已经完全错误。一张牌不应首先定义为两个字符串(例如“Ace”、“Hearts”)。扔掉那些代码,重新考虑并从头开始。
  • 我接受这一点,但我对这里的情况真的很感兴趣,因为书籍或讲师从未提及malloccalloc 可能会如此混乱,并影响之前分配的数据(如果这真的是我的结论)。

标签: c


【解决方案1】:

memset(*cards[i], 0, strlen(*cards[i])); 行是错误的。首先,cards 被分配了calloc,所以它被零字节填充,充当空字符串。所以,如果*cards[i] 指向cards 中的某个内容,strlen 返回零,而memset 将零字节设置为零。

不幸的是,*cards[i] 仅在 i 为零时有效。由于cards 是指向deck_t 的指针,所以cards[0] 是第一个deck_t,它是char 数组的数组。作为一个数组,它会自动转换为指向其第一个元素的指针,即char 的数组。那么*cards[0] 就是char 的数组。作为一个数组,它会自动转换为指向其第一个元素的指针,并传递给strlen。但是,当i 是一个(或更大)时,cards[i] 将是第二个(或更大)deck_t。但是只为一个deck_t 分配了空间。所以*cards[i] 无效;它尝试访问未分配的空间。

由于不需要此行(由于calloc),请删除它以及它所在的循环。

strcat(*cards[j] 中,也存在同样的问题——*cards[j] 只有在j 为零时才有效。正确的表达式是(*cards)[j]

(*cards)[j]中,cards是一个指向deck_t的指针,所以(*cards)是一个deck_t,它是一个char的数组。那么(*cards)[j]是那个数组的元素j,所以它是一个char的数组。

同样,在print_deck 中,将*deck[i] 更改为(*deck)[i]

(可以通过将deck的类型更改为char (*MyType)[S_MAXLEN + V_MAXLEN + OFLEN]来更改代码,以便可以使用deck[i]代替(*deck)[i]。但是,您可能希望先进行上述更改并在了解它们之前改变类型。)

【讨论】:

  • 所以你是说,作为一个指向deck_t的指针,作为deck_t的大小移动的第二个索引,而不是它的数组的第二个元素(第二个字符串)?
  • 但是当我使用(*card)[j] 时,我会先获取数组,然后再访问它的元素
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 2013-07-01
相关资源
最近更新 更多