Как динамически распределять память, не влияя на другие данные, выделяемые динамически? - PullRequest
0 голосов
/ 24 апреля 2019

Я реализую карточную игру с использованием 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;
}

проблема в deck.c в функции сделки. когда я выделяю память для dealed_deck.hand и dealed_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.hand и dealed_deck.remaining_cards, были такими же, как данные, на которые указывают deck, но когда я использовал calloc, они были пусто, как я хочу.

Мне нужен способ выделить память, не испортив память и данные, которые я выделил ранее, как это сделать?

Я компилирую, используя MacOS и gcc. спасибо.

1 Ответ

2 голосов
/ 24 апреля 2019

Линия 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)[i] можно было использовать deck[i], изменив тип с deck на char (*MyType)[S_MAXLEN + V_MAXLEN + OFLEN]. Однако вы можете сначала внести вышеуказанные изменения и понять их, прежде чем менять типы.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...