【问题标题】:Why would accessing this local member variable cause an exception?为什么访问这个局部成员变量会导致异常?
【发布时间】:2014-04-08 08:02:03
【问题描述】:

我正在尝试编写一个程序,该程序将读取 .csv 文件的内容到一个数组中,然后在调用函数 getNumberOfRooms() 时将结果打印到屏幕(较​​大项目的一部分)。它试图返回numberOfRooms 变量的值,这是类中的一个私有成员。以前有没有人遇到过这样的问题或帮助过解决此类问题的人?如果有,你是怎么解决的?

提前致谢,

此处提供完整源代码:https://bitbucket.org/skutov/micropuzzle/

调用getNumberOfRooms()时抛出的异常:

Unhandled exception at 0x01354aa6 in MICROPUZZLE.exe: 0xC0000005: Access violation
reading location 0xccccccd0.

这些是有问题的函数(变量总是在类中被引用)

ClassMap::ClassMap ()
{
    numberOfRooms = 0;

    // Get number of rooms in map.csv

    /* Find number of entries in map.csv file */

        numberOfRooms = number_of_lines;

    // allocate memory for rooms array

    /* loading data from file into array */
    }
}    

// self explanitory
int ClassMap::getNumberOfRooms()
{
    // Exception occurs on this line when accessing the variable
    return numberOfRooms;
}

int ClassMap::printRoomDescriptions ()
{
    for(int j = this->getNumberOfRooms(); j > 0; j--)
    {
        cout << roomArray[j].getDescription();
    }
    return 0;
}

这是类头:

class ClassMap
{
private:
    int currentLocation;
    int numberOfRooms;
    // pointer to array initialised in constructor
    ClassRoom *roomArray;

public:
    // Constructors and Destructors
    ClassMap();
    ~ClassMap();

    // Print description, events and directions for current room
    std::string getCurrentRoom();

    // Change currentLocation to neighbour of current room if possible
    int moveRoom(char direction);


    // self explanitory
    int getNumberOfRooms();

    // dump room descriptions to command line (debugging)
    int printRoomDescriptions();

};

这里是 ClassMap 的构造函数,它也初始化了 roomArray:

ClassMap::ClassMap ()
{
    numberOfRooms = 0;

    // Get number of rooms in map.csv

        unsigned int number_of_lines = 0;
        FILE *infile = fopen("map.csv", "r");
        int ch;

        while (EOF != (ch=getc(infile)))
            if ('\n' == ch)
                ++number_of_lines;
        fclose(infile);
        numberOfRooms = number_of_lines;




    // allocate memory for rooms array
    roomArray = new ClassRoom[numberOfRooms+1];

    // set starting room
    int currentLocation = 1;

    // load that shit up
    {
        // Holders for values read from file
        int newRoomID = 0;
        char newRoomDescription[79] = "";
        int newRoomNorthNeighbour = 0;
        int newRoomEastNeighbour = 0;
        int newRoomSouthNeighbour = 0;
        int newRoomWestNeighbour = 0;

        // used for iterations
        int i = 0;

        // File stream for map.csv
        std::ifstream mapFile;

        // Crack that shit open
        mapFile.open ("map.csv");

        // Line buffer for parsing
        std::string line;


        // For each line in the map.csv file read in the values into variables declared above then run initialise function for each room to store values into array
        while (std::getline(mapFile, line))
        {
            // re-init parameters

            newRoomID = 0;
            newRoomNorthNeighbour = 0;
            newRoomEastNeighbour = 0;
            newRoomSouthNeighbour = 0;
            newRoomWestNeighbour = 0;
            for(i = 0;i<79;i++)
            {
                newRoomDescription[i] = ' ';
            }


            int parameter = 0;

            int paraStart = 0;
            int paraEnd = 0;

            std::string buffer;
            std::istringstream iss(line);

            for(parameter = 0; parameter <= 5; parameter++)
            {
                // Empty buffer from last iteration
                buffer.clear();

                // Find end of current parameter
                paraEnd = line.find(',',paraStart+1);

                switch (parameter)
                {
                case 0:
                    buffer = line.substr((paraStart),(paraEnd-paraStart));
                    newRoomID = atoi(buffer.c_str());
                    break;
                case 1:
                    buffer = line.substr((paraStart+2),(line.find("\"",paraStart+2)-(paraStart+2)));
                    for(i = 0;i<(buffer.length());i++)
                    {
                        newRoomDescription[i] = buffer.c_str()[i];
                    }
                    //newRoomDescription
                    break;
                case 2:
                    buffer = line.substr((paraStart+1),(paraEnd-paraStart));
                    newRoomNorthNeighbour = atoi(buffer.c_str());
                    break;
                case 3:
                    buffer = line.substr((paraStart+1),(paraEnd-paraStart));
                    newRoomEastNeighbour = atoi(buffer.c_str());
                    break;
                case 4:
                    buffer = line.substr((paraStart+1),(paraEnd-paraStart));
                    newRoomSouthNeighbour = atoi(buffer.c_str());
                    break;
                case 5:
                    buffer = line.substr((paraStart+1),(paraEnd-paraStart));
                    newRoomWestNeighbour = atoi(buffer.c_str());
                    break;
                } // switch

                // Cycle paraEnd to paraStart
                paraStart = paraEnd;

            } // for parameters loop

            // Init next room with data
            new (&roomArray[newRoomID]) ClassRoom(  newRoomNorthNeighbour,
                newRoomEastNeighbour,
                newRoomSouthNeighbour,
                newRoomWestNeighbour,
                newRoomDescription);

        } // while !EOF
        // Close the file because we're a good little program and we don't need that shit no more
        mapFile.close();
    }
}

【问题讨论】:

  • 可能是因为this 指针无效。请在您拨打getNumberOfRooms() 的地方显示代码。问题很可能就在那里。
  • 如何初始化 roomArray?你能展示你的构造函数吗?
  • 添加了完整的构造函数。

标签: c++ exception members


【解决方案1】:

这个问题的关键是:

Access violation reading location 0xccccccd0

0xcccccccc 是用于调试模式的特殊值,用于表示未初始化的指针。 (参见How to end up with a pointer to 0xCCCCCCCC )它设置为调试模式以导致这种崩溃 - 这意味着您正在使用的指针尚未设置。正确设置指针后,错误就会消失。 (与0xcccccccc 的细微差别是您尝试在该对象中访问的成员的偏移量。)

添加:

这是你的错误:

ClassRoom* roomArray = static_cast<ClassRoom*>( ::operator new ( sizeof ClassRoom * numberOfRooms ) );

这将创建一个本地roomArray 变量,并隐藏成员变量。你真正想要的是:

roomArray = static_cast<ClassRoom*>( ::operator new ( sizeof ClassRoom * numberOfRooms ) );

或者更好:

roomArray = new ClassRoom[numberOfRooms];

【讨论】:

  • 感谢您的建议,考虑到您的更改,它对程序没有任何影响,只是让它看起来更整洁一些。我已将更改编辑到原始问题中。只是为了确保事情清楚,变量 numberOfRooms 在这种情况下使用得很好,它是导致错误的 get 函数。
  • 代码看起来确实更好,但它仍然充满了奇怪和潜在的错误。 (无法判断它们是否是实际错误,因为我们没有所有代码。)我认为您确实需要创建一个更好的简化代码示例,以便向我们展示您是否需要进一步的帮助。请参阅sscce.org 了解预期内容。
【解决方案2】:

我猜问题出在你的 for 循环 for(int j = this-&gt;getNumberOfRooms(); j &gt; 0; j--) 上。它应该如下所示:for(int j = this-&gt;getNumberOfRooms()-1; j &gt;= 0; j--)。 具有 N 个条目的数组中的最后一个可访问索引是 N-1。另一方面,第一个索引是 0。

【讨论】:

  • 感谢您的指点,不是问题出在哪里,但这确实突出了我编写 .csv 文件的方式的另一个问题。在那里避免了一个潜在的头痛。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 2013-04-24
相关资源
最近更新 更多