如何动态分配内存而不影响其他动态分配的数据?

时间:2019-04-24 10:11:54

标签: c

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

deck.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进行编译。 谢谢。

1 个答案:

答案 0 :(得分:2)

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,它是{{1 }}。然后char是该数组的元素(*cards)[j],因此它是j的数组。

类似地,在char中,将print_deck更改为*deck[i]

(可以更改代码,以便通过将(*deck)[i]的类型更改为deck[i]来使用(*deck)[i]代替deck。但是,您可能希望上面的更改会先发生,并在更改类型之前先了解它们。)