【问题标题】:Linked List Deck of Cards - Access violation reading locationLinked List Deck of Cards - 访问违规读取位置
【发布时间】:2026-01-25 08:45:01
【问题描述】:

所以,我正在尝试使用链接列表为一个班级创建一副牌,但我很难弄清楚为什么会出现错误:访问冲突读取位置 0x00000020。我对编码和动态分配还很陌生,我确信这是一个简单的解决方法,但我终其一生都无法弄清楚。我的 Deck 类是链表,我的 Card 类是节点。最终目标是让游戏成为 Crazy Eights。 Game 类应该有四个牌组(抽牌堆、弃牌堆、我的手、电脑手)。

代码在deck.cpp 中的addCard() 函数中的SIZE++; 中断

甲板.h

    #pragma once
    #include "Card.h"

    class Deck
    {
    protected:
        int SIZE;   //SIZE variable - indicates how many cards in deck
        Card *top;  //pointer to TOP of linked structure of cards

    public:
        //CONSTRUCTOR
        Deck();

        //FILL DECK
        void fill();                        //initialize the Deck to contain the standard 52 cards
        void addCard(int v, string s);      //*insert* a new card into the Deck

        //DRAW CARD
        Card *drawCard();                   //*remove* top card from the Deck and return it

        //FIND AND REMOVE
        void removeCard(int val, string s);//*find* a specific card and remove it from the Deck

        //SHUFFLE
        void shuffle();                     //randomize the order of cards in the Deck

        //PRINT
        void print();                       //displays the contents of the Deck
};

Deck.cpp

#include "Deck.h"
#include "Card.h"
#include <iostream>
using namespace std;

Deck::Deck()
{
    top = NULL;
    SIZE = 0;
}

void Deck::fill()
{
    string suit;
    for (int i = 0; i < 13; i++){
        for (int j = 0; j < 4; j++){
            switch (j){
                case 0: suit = "HEART"; break;
                case 1: suit = "DIAMOND"; break;
                case 2: suit = "CLUB"; break;
                case 3: suit = "SPADE"; break;
            }//end switch
            addCard(i, suit);
        }//end for
    }//end for
}//end fill

Card *Deck::drawCard()  
{
    Card *draw = top;
    top = top->getNext();
    SIZE--;
    return draw;
}//end drawCard

void Deck::removeCard(int val, string s)    
{
    //FINDS CARD
    Card *cur = top;
    while (cur != NULL && cur->getVALUE() != val && cur->getSUIT() != s)
        cur = cur->getNext();
    if (cur != NULL) 
        cout << cur->getVALUE() << cur->getSUIT();
    else{ 
        cout << "NOT FOUND";
        return;
    }//end else

    //REMOVES CARD
    Card *remove, *prev;
    if (top->getVALUE() == val && top->getSUIT() == s){
        remove = top;
        top = top->getNext();
        delete remove;
        SIZE--;
        removeCard(val, s);
    }//end if
    else{
        prev = top;
        while (prev->getNext() != NULL && prev->getNext()->getVALUE() != val && prev->getNext()->getSUIT() != s)
            prev = prev->getNext();
        if (prev->getNext() != NULL){
            remove = prev->getNext();
            prev->setNext(remove->getNext());
            delete remove;
            SIZE--;
            removeCard(val, s);
        }//end if
    }//end else
}//end removeCard

void Deck::addCard(int val, string s)
{
    SIZE++;
    top = new Card(val, s, top);
}//end addCard

//void Deck::shuffle()
//{
//    for (int i = 0; i < 7; i++)
//    {
//        // first break the deck into two half lists  -- like when you
//      //split the deck in half to shuffle
//        Deck half1;
//        Deck half2;
//        for (SIZE; SIZE > SIZE/2; SIZE--)
//        {
//            //draw card off the deck and add card to half1
//          SIZE--;
//        }//end for
//        for (int j = 0; j <= SIZE/2; SIZE++)
//        {
//            //draw card off the deck and add card to half2
//          SIZE++;
//        }//end for
//
//        // now repeatedly pull one card from either half1 or half2 and
//      // place it back on the deck -- like when the cards
//        // are falling back in random clumps during shuffling.
//        // we don't want to draw with 50-50 probability, instead we're
//      // going to skew the probability of selecting from
//        // each pile based on the relative size of the two piles.
//        while (/*half1 and half2 still have cards in them*/true)
//        {
//            int probPile1; //= size of half1 / (size of half1 + size of half2) * 100
//            int randomNum; //= random number between 1 and 100
//            if (randomNum <= probPile1)
//            {
//                //pull a card off half1 and add it back onto the deck
//            }//end if
//            else
//            {
//                //pull a card off half2 and add it back onto the deck
//            }//end else
//        }//end while
//  }//end for
//}//end shuffle

void Deck::print()
{
    cout << "Cards in pile: " << SIZE;
}//end print

卡.h

#pragma once
#include <string>
using namespace std;

class Card
{
    friend class Deck;  //allows Deck class access to Card's private member variables

    protected:
        int VALUE;      //value of card [1,2,3...11,12,13]
        string SUIT;    //HEART, DIAMOND, CLUB, SPADE
        Card *next;

    public:
        //CONSTRUCTORS/DESTRUCTOR
        Card();
        Card(int val, string s, Card *n);
        ~Card();
        Card *copy();

        //SETTERS: VALUE, SUIT, SYMBOL, next
        void setVALUE(int val)  {VALUE = val;}
        void setSUIT(string s)  {SUIT = s;}
        void setNext(Card *n)   {next = n;}

        //GETTERS: VALUE, SUIT, SYMBOL, next
        int getVALUE()          {return VALUE;}
        string getSUIT()        {return SUIT;}
        Card *getNext()         {return next;}

        void displayCard();
};

卡片.cpp

#include "Card.h"
#include <iostream>
using namespace std;

Card::Card()
{
    VALUE = 0; SUIT = " "; next = NULL;
}

Card::Card(int val, string s, Card *n)
{
    VALUE = val; SUIT = s; next = n;
}

Card::~Card()
{
    if(next) free(next);
}

Card *Card::copy()
{
    Card *newCard = new Card(VALUE, SUIT, next);
    return newCard;
}

void Card::displayCard()
{
    cout << VALUE;
}

//tests whether two cards "match" -- comparison operator overload
bool operator == (Card &c1, Card &c2)
{
    return (c1.getVALUE() == c2.getVALUE() || c1.getSUIT() == c2.getSUIT());
}

游戏.h

#pragma once
#include "Deck.h"

class Game
{
    protected:
        Deck *drawPile, *discardPile, *myHand, *compHand;
    public:
        Game();
};

游戏.cpp

#include "Game.h"
#include "Deck.h"

Game::Game()
{
    drawPile = NULL; myHand = NULL; compHand = NULL; discardPile = NULL;

    drawPile->fill();
    for (int i = 0; i < 7; i++){
        myHand->drawCard();
        compHand->drawCard();
    }//end for
    discardPile->drawCard();
}

main.cpp

#include "Game.h"
#include <iostream>
using namespace std;

void main()
{
    Game crazyEights;

    system("PAUSE");
}

【问题讨论】:

  • Decks 必须是指针吗?引用,实际对象不是替代品吗?如果你必须使用指针,智能指针会让你头疼。
  • 我不确定甲板是否应该是指针。
  • 不要让它们成为指针......
  • 我觉得自己太笨了...我花了好几个小时看这个,这就是问题所在...

标签: c++ linked-list dynamic-allocation


【解决方案1】:

这里:

Game::Game()
{
  drawPile = NULL;

  drawPile->fill();
  ...
}

指针drawPile 的值为NULL,但您告诉Deck 它指向(不存在)执行操作。这是取消引用空指针,它会导致未定义的行为

旁注:能够为这样的错误准备minimal complete example 很重要;它将帮助您隔离问题,以便您自己找到问题,或者有一个更简单的程序供我们查看。

【讨论】:

  • 对不起,这是我在这里的第一篇文章。我会确保在未来发布代码 sn-ps。我想我对甲板是否应该是指针感到困惑。当我将它们变成对象时,我不再收到错误消息。我会再做一些测试,谢谢!