经过几个小时和许多尝试调试的咖啡,我和我的朋友们都可以知道出了什么问题。
该程序的快速概述,它是一个用C编写的小型纸牌游戏,并使用链接列表来保存Card
和Deck
中的Hand
。在main()
我有一个循环打印两个玩家的Hand
,然后从他们的Hand
播放随机卡并将其放在Deck
的末尾。为此,我有一个函数playCard()
。
问题是,它打印的Card
是播放器Hand
中不存在的。我只能想象Card
中必须存在Deck
,但我不知道为什么要打印它。我还确保列表的末尾NULL
也可以阻止这样的事情发生。
有谁知道这里出了什么问题?
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct CARD Card;
struct CARD
{
int value;
int id;
Card *next_card;
};
typedef struct Deck
{
int size;
Card *cards;
}Deck;
typedef struct Hand
{
int size;
Card *cards;
}Hand;
Card* createCard();
Deck* createDeck();
Hand* createHand();
int addCard(Card* card, Deck* deck);
int cardExists(int id, Deck* deck);
int cardExistsC(Card* card, Deck* deck);
void shuffle(Deck* deck);
int fillHand(int size, Hand* hand, Deck* deck);
void showHand(Hand* hand);
int playCard(int id, Hand* hand, Deck* deck);
int main(int argc, char** argv)
{
// Initialise seed for random number generator
srand(time(NULL));
int playable = 1;
Deck* deck = createDeck();
Hand* player1 = createHand();
Hand* player2 = createHand();
if (deck == NULL || player1 == NULL || player2 == NULL)
{
if (deck != NULL)
free(deck);
if (player1 != NULL)
free(player1);
if (player2 != NULL)
free(player2);
playable = 0;
}
if (!playable)
{
return -1;
}
else
{
int i = 0;
for (i = 0; i < 52; i++)
{
Card* temp = createCard();
addCard(temp, deck);
}
shuffle(deck);
fillHand(7, player1, deck);
fillHand(7, player2, deck);
for (i = 0; i < 7; i++)
{
showHand(player1);
showHand(player2);
playCard(-1, player1, deck);
playCard(-1, player2, deck);
}
free(deck);
free(player1);
free(player2);
}
return 0;
}
// Create a new card generating a random ID (0-10,000)and value from 0-10
Card* createCard()
{
Card* card = NULL;
card = (Card*)malloc(sizeof(Card));
card->id = rand() % 10000;
card->value = rand() % 10;
card->next_card = NULL;
return card;
}
// Creates a new deck and sets the size to 0, creates a list within the deck
Deck* createDeck()
{
Deck* deck = NULL;
deck = (Deck*)malloc(sizeof(Deck));
deck->size = 0;
deck->cards = NULL;
return deck;
}
// Creates a new hand and sets the size to 0, creates a list within the hand
Hand* createHand()
{
Hand* hand = NULL;
hand = (Hand*)malloc(sizeof(Hand));
hand->size = 0;
hand->cards = NULL;
return hand;
}
// Adds a created card to a deck, returns 1 if card was added, 0 if card wasn't, -1 if a duplicate id was detected
int addCard(Card* card, Deck* deck)
{
// If the deck or the card is not initialised, the card cannot be added
if (deck == NULL || card == NULL) return 0;
// If deck size 0, this must be the first card
if (deck->size == 0)
{
// Add the card and increment the deck size
deck->cards = card;
deck->size++;
// Check if the card was added successfully
if (cardExists(card->id, deck) == 1 || cardExistsC(card, deck) == 1) return 1;
// Returns 0 if card check failed
return 0;
}
// If deck contains at least a card, then add it to the end of the List of cards
if (deck->size > 0)
{
// First check if a duplicate ID exists
if (cardExists(card->id, deck) == 1 || cardExistsC(card, deck) == 1) return -1;
// Traverse to the last card and add the new card
Card *p = deck->cards;
while (p->next_card != NULL)
{
p = p->next_card;
}
p->next_card = card;
deck->size++;
// Check if the card was added successfully
if (cardExists(card->id, deck) == 1 || cardExistsC(card, deck) == 1) return 1;
}
// If nothing runs successfully, return 0
return 0;
}
// Determines if a card exists within a deck given an id or a card* returns 1, otherwise 0
int cardExists(int id, Deck* deck)
{
// If deck is not initialised, return 0
if (deck == NULL) return 0;
// Traverse through the cards checking if the id matches any of the current cards
Card *p = deck->cards;
if (p->id == id) return 1; // Check if id matches the first card
while (p->next_card != NULL)
{
p = p->next_card; // Move on to the next_card
if (p->id == id) return 1; // If id matches, return 1
}
// No duplicate cards return 0
return 0;
}
int cardExistsC(Card* card, Deck* deck)
{
// If deck is not initialised, return
if (deck == NULL || card == NULL) return 0;
// Traverse through the cards checking if the card matches any of the current cards
Card *p = deck->cards;
while (p->next_card != NULL)
{
if (p == card) return 1; // If id matches, return 1
p = p->next_card; // Else move on to the next_card
}
// No duplicate cards return 0
return 0;
}
// Shuffles deck - size*100 randoms swaps, or a shuffling algorithm
void shuffle(Deck* deck)
{
// If deck is not initialised, return
if (deck == NULL) return;
// Declare vars for use
int d, i, j, x, r1, r2;
Card *o = deck->cards; // The List of cards
Card *p1, *p2, *t; // Temp cards
d = deck->size; // Deck size
i = 0; // Loop var
j = d * 100; // Amount of swaps needed
x = 0; // Inner loop var
// Initialise pointers
p1 = NULL;
p2 = NULL;
t = NULL;
// Swaps two cards while less than amount of reqired swaps
while (i < j)
{
// Create two random numbers
r1 = rand() % d;
r2 = rand() % d;
// Traverse through the List od cards in the deck r1 and r2 number of times
while (x <= r1 || x <= r2 && o->next_card != NULL)
{
if (x == r1) p1 = o; // p1 == o when x == r1
if (x == r2) p2 = o; // p2 == o when x == r2
o = o->next_card;
x++;
}
// Hold p1 in t
t = p1;
// Replace p1 with p2
p1->id = p2->id;
p1->value = p2->value;
// Replace p2 with t
p2->id = t->id;
p2->value = t->value;
i++;
}
}
// Moves the top x cards of the deck to the hand structure returns hand size
int fillHand(int size, Hand* hand, Deck* deck)
{
// If deck and hand is not initialised or size less than 0, return
if (deck == NULL || !(size >= 0)) return 0;
// Initialise vars for use
Card *h = hand->cards;
Card *d = deck->cards;
int x = 1;
// Make h == d
h = d;
// Start the hand here
hand->cards = h;
// Traverse 'size' amount through the hand and deck
while (x < size && h->next_card != NULL && d->next_card != NULL)
{
h = h->next_card;
d = d->next_card;
x++;
}
// Update hand->size
hand->size = x;
// Move the card after the new hand list up to be the new top of deck
deck->cards = d->next_card;
deck->size = deck->size - x;
// End the hand here
h->next_card = NULL;
return hand->size;
}
// prints the hand to the console showing ID and value, one card per line in the format ###\tID-Value
void showHand(Hand* hand)
{
// If hand is not initialised, return
if (hand == NULL) return;
// Declare vars for use
int val, id;
Card *p = hand->cards;
// Traverse through the List of Cards printing each one's value and id
while (p->next_card != NULL)
{
val = p->value;
id = p->id;
printf("###\t %d-%d\n", id, val);
p = p->next_card;
}
printf("\n");
}
// Removes the card from hand and displays the card ID and Value in the format ***ID-Value, a value of -1 in id indicates a random card, returns played card id
int playCard(int id, Hand* hand, Deck* deck)
{
// If hand is not initialised, return
if (hand == NULL || deck == NULL) return 0;
// Setup vars for use
Card *d, *h, *p;
int i, cid, cval;
d = deck->cards;
h = hand->cards;
p = h;
i = 0;
// If card is to be randomly chosen
if (id == -1)
{
i = rand() % hand->size; // Get a random number
i++;
while (i > 0 && h->next_card != NULL) // Move i times through the list
{
p = h; // make p == current card so it becomes the previous card
h = h->next_card; // Move to the next card
i--; // Decrement i
}
// Go to end of the deck
while (d->next_card != NULL)
{
d = d->next_card;
}
// Get card data
cid = h->id;
cval = h->value;
// Print the card data
printf("***%d-%d\n\n", cid, cval);
// Put the randomly chosen card from the hand to the end of deck
d->next_card = h;
// Remove the card from hand
p->next_card = h->next_card;
// Move to the card added to the deck
d = d->next_card;
// Ensure the end card is the last in the list
d->next_card = NULL;
// Increment deck size
deck->size++;
// Decrement hand size
hand->size--;
return -1;
}
else
{
// Go to end of the deck
while (d->next_card != NULL)
{
d = d->next_card;
}
// Get card data
cid = h->id;
cval = h->value;
// Print the card data
printf("***%d-%d\n\n", cid, cval);
// Put the randomly chosen card from the hand to the end of deck
d->next_card = h;
// Remove the card from hand and make the following card the new head of the list
hand->cards = h->next_card;
// Move to the card added to the deck
d = d->next_card;
// Ensure the end card is the last in the list
d->next_card = NULL;
// Increment deck size
deck->size++;
// Decrement hand size
hand->size--;
return cid;
}
}
答案 0 :(得分:2)
您的某些循环中存在一些用于访问链接列表的错误。
您的Shuffle
中存在明确的错误,会产生重复的卡片。
我对playCard
进行了粗略的检查,看起来没问题
在我修复了其他一些错误之后,我肯定会得到不同的输出(注意:我更改了srand
以使用固定值,以便您的版本与我的版本之间的比较会工作)
使用-Wall
编译器选项,您的一个while
循环被标记为不明确。我已对其进行了注释,并根据我认为您想要的内容添加了括号。
可能还有其他一些错误,但我已经注释了我能找到的错误。请注意,我使用了以下[尽可能]:
// NOTE/BUG: ...
#if 0
// original code
#else
// fixed code
#endif
无论如何,这是修改后的代码[请原谅无偿风格的清理]:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct CARD Card;
struct CARD {
int value;
int id;
Card *next_card;
};
typedef struct Deck {
int size;
Card *cards;
} Deck;
typedef struct Hand {
int size;
Card *cards;
} Hand;
Card *createCard();
Deck *createDeck();
Hand *createHand();
int addCard(Card *card, Deck *deck);
int cardExists(int id, Deck *deck);
int cardExistsC(Card *card, Deck *deck);
void shuffle(Deck *deck);
int fillHand(int size, Hand *hand, Deck *deck);
void showHand(Hand *hand);
int playCard(int id, Hand *hand, Deck *deck);
int
main(int argc, char **argv)
{
// Initialise seed for random number generator
srand(3);
int playable = 1;
Deck *deck = createDeck();
Hand *player1 = createHand();
Hand *player2 = createHand();
if (deck == NULL || player1 == NULL || player2 == NULL) {
if (deck != NULL)
free(deck);
if (player1 != NULL)
free(player1);
if (player2 != NULL)
free(player2);
playable = 0;
}
if (!playable) {
return -1;
}
int i = 0;
// NOTE/BUG: does not fill deck if a duplicate is found (i.e. ignores
// addCard return)
#if 0
for (i = 0; i < 52; i++) {
Card *temp = createCard();
addCard(temp, deck);
}
#else
for (i = 0; i < 52; i++) {
while (1) {
Card *temp = createCard();
if (addCard(temp, deck) > 0)
break;
printf("DUPLICATE createCard\n");
}
}
#endif
shuffle(deck);
fillHand(7, player1, deck);
fillHand(7, player2, deck);
for (i = 0; i < 7; i++) {
showHand(player1);
showHand(player2);
playCard(-1, player1, deck);
playCard(-1, player2, deck);
}
free(deck);
free(player1);
free(player2);
return 0;
}
// Create a new card generating a random ID (0-10,000)and value from 0-10
Card *
createCard()
{
Card *card = NULL;
card = (Card *) malloc(sizeof(Card));
card->id = rand() % 10000;
card->value = rand() % 10;
card->next_card = NULL;
return card;
}
// Creates a new deck and sets the size to 0, creates a list within the deck
Deck *
createDeck()
{
Deck *deck = NULL;
deck = (Deck *) malloc(sizeof(Deck));
deck->size = 0;
deck->cards = NULL;
return deck;
}
// Creates a new hand and sets the size to 0, creates a list within the hand
Hand *
createHand()
{
Hand *hand = NULL;
hand = (Hand *) malloc(sizeof(Hand));
hand->size = 0;
hand->cards = NULL;
return hand;
}
// Adds a created card to a deck, returns 1 if card was added, 0 if card wasn't, -1 if a duplicate id was detected
int
addCard(Card *card, Deck *deck)
{
// If the deck or the card is not initialised, the card cannot be added
if (deck == NULL || card == NULL)
return 0;
// If deck size 0, this must be the first card
if (deck->size == 0) {
// Add the card and increment the deck size
deck->cards = card;
deck->size++;
// Check if the card was added successfully
// NOTE/BUG: superfluous check -- this will always return 1
if (cardExists(card->id, deck) == 1 || cardExistsC(card, deck) == 1)
return 1;
// Returns 0 if card check failed
// NOTE/BUG: otherwise, this is _fatal_
return 0;
}
// If deck contains at least a card, then add it to the end of the List of cards
if (deck->size > 0) {
// First check if a duplicate ID exists
if (cardExists(card->id, deck) == 1 || cardExistsC(card, deck) == 1)
return -1;
// Traverse to the last card and add the new card
Card *p = deck->cards;
while (p->next_card != NULL) {
p = p->next_card;
}
p->next_card = card;
deck->size++;
// Check if the card was added successfully
if (cardExists(card->id, deck) == 1 || cardExistsC(card, deck) == 1)
return 1;
}
// If nothing runs successfully, return 0
return 0;
}
// Determines if a card exists within a deck given an id or a card* returns 1, otherwise 0
int
cardExists(int id, Deck *deck)
{
// If deck is not initialised, return 0
if (deck == NULL)
return 0;
// Traverse through the cards checking if the id matches any of the current cards
Card *p = deck->cards;
#if 0
if (p->id == id)
return 1; // Check if id matches the first card
while (p->next_card != NULL) {
p = p->next_card; // Move on to the next_card
if (p->id == id)
return 1; // If id matches, return 1
}
if (p->id == id)
return 1; // Check if id matches the first card
#else
while (p != NULL) {
if (p->id == id)
return 1; // If id matches, return 1
p = p->next_card; // Move on to the next_card
}
#endif
// No duplicate cards return 0
return 0;
}
int
cardExistsC(Card *card, Deck *deck)
{
// If deck is not initialised, return
if (deck == NULL || card == NULL)
return 0;
// Traverse through the cards checking if the card matches any of the current cards
Card *p = deck->cards;
#if 0
while (p->next_card != NULL) {
if (p == card)
return 1; // If id matches, return 1
p = p->next_card; // Else move on to the next_card
}
#else
while (p != NULL) {
if (p == card)
return 1; // If id matches, return 1
p = p->next_card; // Else move on to the next_card
}
#endif
// No duplicate cards return 0
return 0;
}
// Shuffles deck - size*100 randoms swaps, or a shuffling algorithm
void
shuffle(Deck *deck)
{
// If deck is not initialised, return
if (deck == NULL)
return;
// Declare vars for use
int d,
i,
j,
x,
r1,
r2;
Card *o = deck->cards; // The List of cards
Card *p1, *p2;
d = deck->size; // Deck size
i = 0; // Loop var
j = d * 100; // Amount of swaps needed
x = 0; // Inner loop var
// Initialise pointers
p1 = NULL;
p2 = NULL;
// Swaps two cards while less than amount of reqired swaps
while (i < j) {
// Create two random numbers
r1 = rand() % d;
r2 = rand() % d;
// Traverse through the List od cards in the deck r1 and r2 number of times
// NOTE/BUG: this gets flagged by the compiler with -Wall and really
// is ambiguous:
// which is it?
// while (((x <= r1) || (x <= r2)) && (o->next_card != NULL))
//
// while ((x <= r1) || ((x <= r2) && (o->next_card != NULL)))
#if 0
while (x <= r1 || x <= r2 && o->next_card != NULL) {
#else
while (((x <= r1) || (x <= r2)) && (o->next_card != NULL)) {
#endif
if (x == r1)
p1 = o; // p1 == o when x == r1
if (x == r2)
p2 = o; // p2 == o when x == r2
o = o->next_card;
x++;
}
// NOTE/BUG!!! -- this does _not_ preserve the values correctly for the
// swap
#if 0
// Hold p1 in t
Card *t; // Temp cards
t = p1;
// Replace p1 with p2
p1->id = p2->id;
p1->value = p2->value;
// Replace p2 with t
p2->id = t->id;
p2->value = t->value;
#else
// Hold p1 in t
Card t; // Temp cards
t = *p1;
// Replace p1 with p2
p1->id = p2->id;
p1->value = p2->value;
// Replace p2 with t
p2->id = t.id;
p2->value = t.value;
#endif
i++;
}
}
// Moves the top x cards of the deck to the hand structure returns hand size
int
fillHand(int size, Hand *hand, Deck *deck)
{
// If deck and hand is not initialised or size less than 0, return
if (deck == NULL || !(size >= 0))
return 0;
// Initialise vars for use
Card *h = hand->cards;
Card *d = deck->cards;
int x = 1;
// Make h == d
h = d;
// Start the hand here
hand->cards = h;
// Traverse 'size' amount through the hand and deck
while (x < size && h->next_card != NULL && d->next_card != NULL) {
h = h->next_card;
d = d->next_card;
x++;
}
// Update hand->size
hand->size = x;
// Move the card after the new hand list up to be the new top of deck
deck->cards = d->next_card;
deck->size = deck->size - x;
// End the hand here
h->next_card = NULL;
return hand->size;
}
// prints the hand to the console showing ID and value, one card per line in the format ###\tID-Value
void
showHand(Hand *hand)
{
// If hand is not initialised, return
if (hand == NULL)
return;
// Declare vars for use
int val,
id;
Card *p = hand->cards;
// Traverse through the List of Cards printing each one's value and id
// NOTE/BUG: would fail if only one card in hand
#if 0
while (p->next_card != NULL) {
val = p->value;
id = p->id;
printf("###\t %d-%d\n", id, val);
p = p->next_card;
}
#else
while (p != NULL) {
val = p->value;
id = p->id;
printf("###\t %d-%d\n", id, val);
p = p->next_card;
}
#endif
printf("\n");
}
// Removes the card from hand and displays the card ID and Value in the format ***ID-Value, a value of -1 in id indicates a random card, returns played card id
int
playCard(int id, Hand *hand, Deck *deck)
{
// If hand is not initialised, return
if (hand == NULL || deck == NULL)
return 0;
// Setup vars for use
Card *d,
*h,
*p;
int i,
cid,
cval;
d = deck->cards;
h = hand->cards;
p = h;
i = 0;
// If card is to be randomly chosen
if (id == -1) {
i = rand() % hand->size; // Get a random number
i++;
while (i > 0 && h->next_card != NULL) // Move i times through the list
{
p = h; // make p == current card so it becomes the previous card
h = h->next_card; // Move to the next card
i--; // Decrement i
}
// Go to end of the deck
while (d->next_card != NULL) {
d = d->next_card;
}
// Get card data
cid = h->id;
cval = h->value;
// Print the card data
printf("***%d-%d\n\n", cid, cval);
// Put the randomly chosen card from the hand to the end of deck
d->next_card = h;
// Remove the card from hand
p->next_card = h->next_card;
// Move to the card added to the deck
d = d->next_card;
// Ensure the end card is the last in the list
d->next_card = NULL;
// Increment deck size
deck->size++;
// Decrement hand size
hand->size--;
return -1;
}
else {
// Go to end of the deck
while (d->next_card != NULL) {
d = d->next_card;
}
// Get card data
cid = h->id;
cval = h->value;
// Print the card data
printf("***%d-%d\n\n", cid, cval);
// Put the randomly chosen card from the hand to the end of deck
d->next_card = h;
// Remove the card from hand and make the following card the new head of the list
hand->cards = h->next_card;
// Move to the card added to the deck
d = d->next_card;
// Ensure the end card is the last in the list
d->next_card = NULL;
// Increment deck size
deck->size++;
// Decrement hand size
hand->size--;
return cid;
}
}