Reputation: 160
Im implementing a card game using C, here's my code:
#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
#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';
}
}
}
#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;
}
the problem is deck.c in the deal function.
when I allocate memory for dealed_deck.hand
and dealed_deck.remaining_cards
the data pointed to by the parameter deck
is affected and changed, so when I comment the two lines:
dealed_deck.hand = calloc(1, sizeof(deck_t));
and dealed_deck.remaining_cards = calloc(1, sizeof(deck_t));
, the data is the same, when I uncomment the data change a bit.
I'm using calloc
here because when I used malloc the data pointed to by dealed_deck.hand
and dealed_deck.remaining_cards
was the same as the data pointed to by deck
, but when I used calloc
they were empty as I want.
I need a way to allocate memory without messing the memory and data I allocated before, how to do that?
I'm compiling using a MacOS and gcc. thanks.
Upvotes: 0
Views: 63
Reputation: 224311
The line memset(*cards[i], 0, strlen(*cards[i]));
is wrong. First, cards
was allocated with calloc
, so it is filled with zero bytes, which act as empty strings. So, if *cards[i]
pointed to something in cards
, strlen
returns zero, and memset
sets zero bytes to zero.
Unfortunately, *cards[i]
is valid only when i
is zero. Since cards
is a pointer to a deck_t
, cards[0]
is the first deck_t
, which is an array of array of char
. As an array, it is automatically converted to a pointer to its first, element, an array of char
. Then *cards[0]
is that array of char
. As an array, it is automatically converted to a pointer to its first element, which is passed to strlen
. However, when i
is one (or greater), cards[i]
would be the second (or greater) deck_t
. But space for only one deck_t
was allocated. So *cards[i]
is invalid; it attempts to access space that was not allocated.
Since this line is not needed (due to calloc
), remove it and the loop it is in.
In strcat(*cards[j]
, the same problem exists—*cards[j]
is valid only when j
is zero. A correct expression is (*cards)[j]
.
In (*cards)[j]
, cards
is a pointer to a deck_t
, so (*cards)
is a deck_t
, which is an array of array of char
. Then (*cards)[j]
is element j
of that array, so it is an array of char
.
Similarly, in print_deck
, change *deck[i]
to (*deck)[i]
.
(The code can be changed so that deck[i]
can be used instead of (*deck)[i]
by changing the type of deck
to char (*MyType)[S_MAXLEN + V_MAXLEN + OFLEN]
. However, you may wish to make the above changes first and understand them before changing types.)
Upvotes: 2