Mancala 程序显示正确输出但 valgrind 显示错误

Mancala program showing correct output but valgrind showing errors

我有一项任务是复制宝石棋。游戏规则与原版略有不同,具体如下:

The active player removes all stones from a pit on their side of the board and distributes them counter-clockwise around the board.

Distribution includes the player's goal, but not the opponent's goal.

If distribution ends in the player's goal, they take another turn.

If distribution ends on the player's side, in a previously empty pit, the last stone and any stones immediately across the board are moved to active player's goal (and their turn ends).

If a player's side of the board is empty (not including their goal), any remaining stones are collected by the opponent and the game is over.

不久前我没有通过作业,但我仍在努力弄清楚为什么我错了。该程序输出正确,但我的学校要求我们使用名为 valgrind 的编程工具,这就是问题所在。

为什么 valgrind 会给我这个错误

==5098== Conditional jump or move depends on uninitialised value(s)
==5098==    at 0x49ACB33: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:892)
==5098==    by 0x49BC4FC: put (locale_facets.h:2395)
==5098==    by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098==    by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098==    by 0x1092B7: main (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098== 
==5098== Use of uninitialised value of size 8
==5098==    at 0x49AB01B: int std::__int_to_char<char, unsigned long>(char*, unsigned long, char const*, std::_Ios_Fmtflags, bool) (locale_facets.tcc:821)
==5098==    by 0x49ACB5E: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:894)
==5098==    by 0x49BC4FC: put (locale_facets.h:2395)
==5098==    by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098==    by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098==    by 0x1092B7: main (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098== 
==5098== Conditional jump or move depends on uninitialised value(s)
==5098==    at 0x49AB02D: int std::__int_to_char<char, unsigned long>(char*, unsigned long, char const*, std::_Ios_Fmtflags, bool) (locale_facets.tcc:824)
==5098==    by 0x49ACB5E: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:894)
==5098==    by 0x49BC4FC: put (locale_facets.h:2395)
==5098==    by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098==    by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098==    by 0x1092B7: main (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098== 
==5098== Conditional jump or move depends on uninitialised value(s)
==5098==    at 0x49ACB94: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (locale_facets.tcc:914)
==5098==    by 0x49BC4FC: put (locale_facets.h:2395)
==5098==    by 0x49BC4FC: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5098==    by 0x10948C: Mancala::getBoard[abi:cxx11]() (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098==    by 0x1092B7: main (in /home/oddstap/Documents/2.C++/Projects/malacala/Newest mancala/new/mancala)
==5098== 

mancala.h

#include <iostream>
#include <sstream>

class Mancala
{
    int gameBoard[14];
    int playerS;
    int getGoal(int p);


    public:
        Mancala();
        std::string getBoard();
        int getPlayer();
        int getScore(int player);
        bool move(int n);
};

mancala.cpp

#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "mancala.h"

Mancala::Mancala()
{
    playerS = 0;
    for (int i{0}; i < 14; ++i) //set up the intial board
    {
        if (i == 6 || i == 13)
        {
            gameBoard[i] = 0;
        }
        else 
        {
            gameBoard[i] = 4;    
        }
    }
}

std::string Mancala::getBoard() //return the gameboard in the correct mancala format
{
    std::stringstream ss;
    ss << std::setw(2) << std::right << gameBoard[13];
    ss << " |";
    for (int i{0}; i < 6; ++i)
    {
        ss << std::setw(3) << std::right << gameBoard[12 - i];
    }
    ss << " |";
    if (playerS == 0)
    {
        ss << "  *\n - |";
    }
    else if (playerS == 1)
    {
        ss << "  -\n * |";
    }
    else  
    {
        ss << "  -\n - |";
    }
    for (int j{0}; j < 6; ++j)
    {
        ss << std::setw(3) << std::right << gameBoard[j];
    }
    ss << " |" << std::setw(3) << std::right << gameBoard[6] << "\n";
    return ss.str();
}

int Mancala::getPlayer()
{
    return playerS;
}

int Mancala::getScore(int player)
{
    return gameBoard[getGoal(player)];
}

int Mancala::getGoal(int p)
{
    if (p == 0)
    {
        return 6;
    }
    else  
    {
        return 13;
    }
}

bool Mancala::move(int n)
{
    int pos = getGoal(playerS) - n;
    int current = gameBoard[pos];
    gameBoard[pos] = 0;
    if (current == 0)   //this isn't an allowed move
    {
        return false;
    }
    for (int i{0}; i < current; ++i)
    {
        pos = (pos + 1) % 14;
        if (playerS == 1 && pos == 6)  //skips other goal 
        {
            ++pos;
        }   
        ++gameBoard[pos];
    }

    int mirror{gameBoard[12 - pos]};

    if (gameBoard[pos] == 1 && playerS == 0 && pos < 6)   
    {
        gameBoard[pos] = 0;
        gameBoard[6] += (mirror + 1);
        gameBoard[12 - pos] = 0;
        playerS = 1 - playerS;
    }
    if (gameBoard[pos] == 1 && playerS == 1 && pos > 6) //tests for player 1
    {
        gameBoard[pos] = 0;
        gameBoard[13] += (1 + mirror);
        gameBoard[12 - pos] = 0;
        playerS = 1 - playerS;
    }
    if (pos != getGoal(playerS))
    {
        playerS = 1 - playerS;  //change turns
    }

    int count{};
    int count1{};
    
    for (int k{0}; k < 6; ++k)  //lines 123-159 test each side of board for a 0. If whole side is 0, other player wins and collects all marbles on their side
    {
        if (gameBoard[k] == 0)
        {
            ++count;
        } else{
            count = 0;
        }
    }
    for (int l{0}; l < 6; ++l)
    {
        if (gameBoard[12 - l] == 0)
        {
            ++count;
        } else{
            count1 = 0;
        }
    }
    if (count >= 6)
    {
        playerS = -1;
        for (int m{0}; m < 6; ++m)
        {
            gameBoard[13] += gameBoard[12 - m];
            gameBoard[12 - m] = 0;
            
        }
    } else if (count1 >= 6){
        playerS = -1;
        for (int z{0}; z < 6; ++z)
        {
            gameBoard[6] += gameBoard[z];
            gameBoard[z] = 0;
        }
    }
    return true;
}

main.cpp

#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "mancala.h"

int main()
{
    Mancala m;
    int moves[] = { 4,1,5,3,2 };
    for (int i:moves){
        m.move(i);
        std::cout << m.getBoard() << "\n";
    }
}

我很难自己找到问题。

主要困难在于 valgrind 有效地发现了这一行的问题:

    ss << std::setw(2) << std::right << gameBoard[13];

但这不是真正发生错误的地方。

它不经常发生(但它发生了!),但 valgrind 之前错过了 out-of-bound 访问,在 move(.) 函数中:

    int mirror{gameBoard[12 - pos]};

pos == 13.

当 valgrind 找不到错误发生的地方时,我通常会发现很难(而且很慢)使用调试器。
相反,我通过在代码中插入一些输出来更快地发现问题。

问题似乎已解决:

int mirror = 0;
if (pos <= 12) mirror = gameBoard[12 - pos];