c++混淆状态变量行为

Posted

技术标签:

【中文标题】c++混淆状态变量行为【英文标题】:c++ confusing state variable behaviour 【发布时间】:2018-04-09 17:15:35 【问题描述】:

我有一个类“CardT”,它包含一个由枚举值存储的花色和数字。对于纸牌的使用,我创建了一副由 52 张这样的卡片组成的牌组,每个值都有。我还有一个“tableau”类,它为纸牌游戏存储一组这些卡片,我的 board 类包含其中 8 个的数组。将值放入数组并打印以检查正确性后,它会给出正确的输出。但是,如果我在打印完全相同的内容之后立即调用另一个函数,我会得到非常不同的值。

int main()
    Board b;
    b.setUp();  //setUp deck and add to tableau arrays
    b.printTab(4); //print the fourth one again

甲板设置的地方

void Board::setUp()
//here i setup all 52
CardT deck[52];
int c = 0;
for (int i = 0; i <= 3; i++)
    for (int j = 1; j <=13;j++)
        deck[c] = CardT(static_cast<CardSuit>(i),static_cast<CardNum>(j));
        c++;
    
//shuffle
std::random_shuffle(&deck[0],&deck[52]);

CardT tabls[8][13]; 
for (int i = 0; i < 4; i++)
    for (int j = 0; j < 8; j++)
        tabls[i][j] = deck[j + i*8];  //the first 4 piles that contain 8 cards

for (int i = 4; i < 8; i++)
    for (int j = 0; j < 7;j++)
        tabls[i][j] = deck[j + i*8]; //last four with seven

for (int i = 0; i < 4; i++)
    this->tableauPiles[i] = TableauPileT(tabls[i],8); //place first four, (second param is size)

for (int i = 4; i < 8; i++)
    this->tableauPiles[i] = TableauPileT(tabls[i],7); //place second four

for (int i = 0; i < 4;i++)
    this->foundationPiles[i] = FoundationPileT(); //just intialize


//FOR testing
for (int j = 0; j < 13; j++)
    if (this->tableauPiles[4].cardAtIndex(j))
        std::cout << this->tableauPiles[4].getCardByIndex(j).getNum() << ",,,," << this->tableauPiles[4].getCardByIndex(j).getSuit() << std::endl;

    

//printed twice for assurance, both print as expected
for (int j = 0; j < 13; j++)
    if (this->tableauPiles[4].cardAtIndex(j))
        std::cout << this->tableauPiles[4].getCardByIndex(j).getNum() << ",,-,," << this->tableauPiles[4].getCardByIndex(j).getSuit() << std::endl;

    




在这里我再次打印完全相同的东西:

void Board::printTab(int i)
    for (int j = 0; j < 13; j++)
        if (this->tableauPiles[4].cardAtIndex(j))
            std::cout << this->tableauPiles[4].getCardByIndex(j).getNum() << ",,Third,," << this->tableauPiles[4].getCardByIndex(j).getSuit() << std::endl;
    

板的标题

#ifndef BOARD_H
#define BOARD_H

class Board
private:

CardT freeCells[4];
bool freeCellsOpen[4] = false,false,false,false;
FoundationPileT foundationPiles[4];
TableauPileT tableauPiles[8];

int cardPosition(CardNum n, CardSuit s);
int emptyFreeCell();

public:

Board();
void setUp();
void moveToFreeCell(CardNum n, CardSuit s);
void moveToTableau(CardNum n, CardSuit s, int tableau);
void moveToFoundation(CardNum n, CardSuit s);
void printBoard();
void printTab(int i);
;


#endif

最后这就是我给出的输出

1,,,,1
12,,,,2
4,,,,0
4,,,,1
4,,,,2
5,,,,3
10,,,,0
1,,-,,1
12,,-,,2
4,,-,,0
4,,-,,1
4,,-,,2
5,,-,,3
10,,-,,0
1,,Third,,1
0,,Third,,1
0,,Third,,0
32545,,Third,,1284192187
0,,Third,,10
32767,,Third,,1922833024
0,,Third,,0

打印的值存储为枚举。

在 print 语句之间明显改变,对 c++ 很新,但有 c 经验。非常感谢任何帮助,因为我已经疯了。

我也在打印第 4 堆,我相信 0-3 堆都打印正确,只有 4+ 被弄乱了。

另外值得注意的是,较大的意外值在执行之间会发生变化,其余保持不变。

【问题讨论】:

你为什么将这一行 std::cout &lt;&lt; (int) this-&gt;tableauPiles[4].getCardByIndex(j).getNum() &lt;&lt; ",,Third,," &lt;&lt; (int) this-&gt;tableauPiles[4].getCardByIndex(j).getSuit() &lt;&lt; std::endl; 转换为整数,但没有其他打印输出? 当您对卡片进行分配时,例如this-&gt;tableauPiles[i] = TableauPileT(tabls[i],8);,您是否在进行深层复制?如果不是,这些东西就会超出范围,您会看到随机内存 我认为您发布的代码没有问题。你能试着准备一个minimal reproducible example吗?将所有内容放在一个文件中,删除不需要的内容。 codepad.org/IoqQvO1c @AndreasHaferburg 你可以在你的评论中加入[mcve],它会生成一个这样的链接:minimal reproducible example @melpomene 很酷,谢谢。 :) 【参考方案1】:

您的牌桌 (CardT tabls[8][13];) 在您的 Board::setUp() 方法的堆栈中声明。

然后,您将指向这些的指针存储在 TableauPileT 对象中。 这适用于您的调试代码,因为它们仍在堆栈中, 但在您调用 printTab 函数时,它们已被释放。

因此,此时您只是在读取内存中剩余的任何内容,这意味着您将获得未定义的行为。

【讨论】:

好吧有道理,我的时间差距,因为 c 显示清楚。我将如何为此做一个深拷贝?还是需要明确完成 我建议最好在 TableauPile 中使用 std::vector。如果不是这样,则将表声明为 Board 对象的成员,而不是在堆栈中。 不仅仅是表格,您还希望CardT deck[52]; 成为您的板对象的一部分。您的问题是TableauPileT 有一个指向卡片列表的指针,这些卡片在堆栈中。从该方法返回时,这现在是随机内存。【参考方案2】:

洗牌后的第二个循环:为什么你把 i 乘以 8 而堆只有 6 张牌?显然超出了数组范围。应该是[j+4+i*6]。顺便说一句,前 4 堆只有 7 张牌长,i 乘以 8 是错误的。在那些表启动循环中,j 应该分别小于 7 和 6,而不是 8 和 7。

【讨论】:

是的,我更改了所有范围等,一旦打印开始工作并且我可以看到。谢谢! 不客气。但很可能,我不会写那样的代码。可以做很多事情来提高这段代码的质量,但是我太老了?。

以上是关于c++混淆状态变量行为的主要内容,如果未能解决你的问题,请参考以下文章

Verilog三段式状态机描述

混淆 C++ 语言中的字符串重复

C++基本语法

Visual Studio C++ 编译器在局部变量对象上的奇怪行为

C++引用

如果变量 a 是 char 数组是 char* p = &a 在 C++ 中定义的行为