【问题标题】:Fatal error from incrementing loop来自递增循环的致命错误
【发布时间】:2011-03-30 11:31:56
【问题描述】:

目前,我正在尝试在 Fighter.cpp 文件中的函数 sortFighters 中创建一个对充满战斗机的向量进行排序的函数。一切似乎都正确编译了;但是,当它运行时,我在上述 .cpp 文件的其中一行中遇到了一个致命错误。我确切地知道问题是什么,并相应地在那里发表评论。 所以,我在这里要问的是,在不添加任何其他功能等的情况下,我可以做些什么来解决这个问题。

这是我的 Fighter.h 文件:

#ifndef FIGHTER_H
#define FIGHTER_H

#include <iostream>
#include <ctime>
#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>

class Fighter
{   
protected:
        std::string name;
        int health, level;
        //int damage;
public: 
        int  getHealth(int);
        void getEnemies(std::vector<Fighter> &);
        void printFighter(std::vector<Fighter> &);
        void sortFighters(std::vector<Fighter> &);
        //friend std::istream & operator >> (std::istream & strm, Fighter & x);
        //friend std::ostream & operator << (std::ostream & strm, const Fighter & f);
        //void attack();
        Fighter();
        ~Fighter();
};

class Player : public Fighter 
{ 
    private:
        int experience;
    public:
        int  getHealth(int);
        void pri`enter code here`ntFighter();
        void getExperience(int);
        void playerAttack();    
        Player();
        ~Player();
};

//class FightPub
//{
//  private:
//      Player player;
//      Fighter enemy;
//  public:
//      //void fight();
//      //void getStats();
//};
#endif

我的 Fighter.cpp 文件:

//dynamically locate an array that holds the number of fighters, and for each fighter in the array, assign from the .txt 
//file the name and level from the fighter.
#include "Fighter.h"  

#pragma region getEnemies
void Fighter::getEnemies(std::vector<Fighter> &baddie)
{
    Fighter x;
    std::ifstream inputFile;
    inputFile.open("EnemyFighters.txt");
    if(!inputFile)
    {
        std::cout << "error!" << std::endl;
    }
    else
    {
        while(!inputFile.eof())
        {
            std::string line;
            inputFile >> line;
            if (line == "<fighter>")
            {
                do
                {
                    inputFile >> line;
                    x.name = line;
                    inputFile >> line;
                    x.level = atoi(line.c_str());
                    inputFile >> line;
                    x.health = getHealth(this->level);
                    baddie.push_back(x);
                    inputFile >> line;
                }while(line != "</fighter>");
            }                   
        }
        inputFile.close();
    }
}
#pragma endregion

#pragma region getHealth

int Fighter::getHealth(int lv)
{
    if(lv >= 6)
    {
        std::cout << "\nHealth Bonus!";
        this->health = lv * 2;
    }
    /*else if (lv > 1)
        for (int i = 1; i < lv; i++)
        {this->health += 2;}*/
    return health;
}

#pragma endregion

#pragma region attack
//void Fighter::attack()
//{
//  int randomAttack = rand() % 4 + 1;
//
//  switch (randomAttack)
//  case 1: 
//  {
//      std::cout << "Enemy uses critical attack!"
//  }
//}
#pragma endregion

#pragma region printFighter
void Fighter::printFighter(std::vector<Fighter> &baddie)
{
    //std::cout << this;
    for (int i=0; i<baddie.size(); i++)
    {
        std::cout << "\nName: " << baddie[i].name << std::endl
                  << "Level: " << baddie[i].level << std::endl
                  << "Health: " << baddie[i].health << std::endl;
    }
}
#pragma endregion

void Fighter::sortFighters(std::vector<Fighter> &x)
{
    Fighter * temp = new Fighter;
    bool swap;

    do
    {
        swap = false;
        std::cout << x.size() << std::endl;
        for (int i=0; i<=(x.size()); i++)
        {
            //if the level in the first is greater than the level in the next
            if(x[i].level > x[i+1].level)//I get a fatal error here when it tries to compare 
                                         //the iterator with 1 that's outside its range
            {
                //assign the stats from the first to temp
                temp->name = x[i].name;
                temp->health = x[i].health;
                temp->level = x[i].level;
                //assign the stats from the next to the first
                x[i].name = x[i+1].name;
                x[i].health = x[i+1].health;
                x[i].level = x[i+1].level;
                //assign the ones in temp(the first) to the next
                x[i+1].name = temp->name;
                x[i+1].health = temp->health;
                x[i+1].level = temp->level;
                swap = true;
            }

            else if(x[i].level >= x[i+1].level)
            {
                temp->name = x[i].name;
                temp->health = x[i].health;
                temp->level = x[i].level;

                x[i].name = x[i+1].name;
                x[i].health = x[i+1].health;
                x[i].level = x[i+1].level;

                x[i+1].name = temp->name;
                x[i+1].health = temp->health;
                x[i+1].level = temp->level;
                swap = true;
            }

            else if (x[i].level < x[i+1].level)
            {
                //temp->name = x[i].name;
                //temp->health = x[i].health;
                //temp->level = x[i].level;

                //x[i].name = x[i+1].name;
                //x[i].health = x[i+1].health;
                //x[i].level = x[i+1].level;

                //x[i+1].name = temp->name;
                //x[i+1].health = temp->health;
                //x[i+1].level = temp->level;
                swap = false;
            }

            else if(x[i].level <= x[i+1].level)
            {
                /*temp->name = x[i].name;
                temp->health = x[i].health;
                temp->level = x[i].level;

                x[i].name = x[i+1].name;
                x[i].health = x[i+1].health;
                x[i].level = x[i+1].level;

                x[i+1].name = temp->name;
                x[i+1].health = temp->health;
                x[i+1].level = temp->level;*/
                swap = false;
            }
        }
    }while (swap);

    delete temp;
}
//std::istream & operator >>(std::istream & strm, Fighter x)
//{
//  //x.name += strm.c_str();
//  //x.level += atoi(strm.c_str());
//  strm >> x.name;
//  strm >> x.level;
//  return strm;
//}

//std::ostream & operator << (std::ostream & strm, const Fighter f)
//{
//  strm << "Name: " << f.name << std::endl;
//  strm << "Level: " << f.level << std::endl;
//  strm << "Health: " << f.health << std::endl;
//  return strm;
//}
#pragma region Fighter C&D
Fighter::Fighter()
{
    level = 1;
    health = 10;
}
Fighter::~Fighter()
{
}
#pragma endregion
//void operator <()
//{
//}
//
//void operator >()
//{
//}
//
//void operator <=()
//{
//}
//
//void operator >=()
//{
//}
//
//
//
int Player::getHealth(int lv)
{
    if(lv >= 6)
    {
        std::cout << "\nHealth Bonus!";
        this->health = lv * 2;
    }
    /*else if (lv > 1)
        for (int i = 1; i < lv; i++)
        {this->health += 2;}*/
    return health;
}

void Player::printFighter()
{
//std::cout << this;
      std::cout << "\nPlayer's stats: \n"
      << "Level: " << this->level << std::endl
      << "Health: " << this->health << std::endl
      << "Experience: " << this->experience <<std::endl;
}

void Player::getExperience(int dmg)
{
    experience += dmg;
    if (experience >= (level * 10))
    {
        std::cout << "Congratulations, Player! You're up a level!\n";
        level ++;
    }
}

#pragma region Player C&D
Player::Player()
{
    level = 1;
    health  = getHealth(level);
    experience = 0;
}
Player::~Player()
{
}
#pragma endregion 


//Player::printFighter()
//{
//  
//}

这是 main.cpp:

#include "Fighter.h"

int main()
{   
    unsigned seed = time(0);
    srand(seed);

    std::vector<Fighter> baddie;

    Fighter * enemy = new Fighter;
    Player * me = new Player;
    enemy->getEnemies(baddie);
    enemy->sortFighters(baddie);
    enemy->printFighter(baddie);
    me->printFighter();
    delete enemy;
    delete me;
    return 0;
}

【问题讨论】:

  • 没有理由自己实现排序例程,因为您可以将std::sort 与自定义谓词一起使用。 - 如果要交换值,可以使用std::swap(顺便说一句,应该重载并且对字符串更有效)。 - 没有理由动态分配临时变量,只需使用常规局部变量(您也不应该单独交换每个成员)。 - 事实上,我也怀疑你的 swap 变量的逻辑是错误的(最后一对是为了退出排序循环)。

标签: c++ loops vector runtime-error fatal-error


【解决方案1】:
    for (int i=0; i<=(x.size()); i++) 
    { 
        if(x[i].level > x[i+1].level)
        {

嗯.. Size() 从 1 开始计数。索引从 0 开始计数。所以你会想要 i &lt; x.size(),而不是 &lt;=但是,在下一行,你说x[i+1],所以i 甚至无法到达最后一项,它必须在此之前停止:

    for (int i=0; i < x.size()-1; i++) 

【讨论】:

  • 是的,虽然i &lt; x.size() - 1 会在x.size() == 0 失败。
  • 更好用i+1 &lt; x.size()
  • @josh:那怎么会失败?一开始,i &lt; size() -1 变成了0 &lt; -1,所以循环永远不会进入(因为它不应该)
  • @James:size() 是无符号的,所以size() - 1 是一个非常大的正数。
  • @James:你确定吗?我能找到的每个参考资料都说size_type 是实现定义的无符号整数类型,在我的 Visual C++ 2010 副本中,它是无符号的。无论如何,避免使用size() - 1 更便于携带。
【解决方案2】:

尝试将你的 for 循环更改为此

for (int i=0; i < x.size() - 1; i++) {
  ... your original content...
}

这样x[i+1] 永远不会越界
您正在尝试访问尚未分配的内存。

【讨论】:

    【解决方案3】:

    你的问题在于这个循环:

    for (int i=0; i<=(x.size()); i++){ 
        if(x[i].level > x[i+1].level){  //Fatal Error Here 
            // Do some stuff
        }
        // Do some more stuff
    }
    

    终止外循环的条件是i&lt;=(x.size()),这意味着当您进行中断程序的比较(x[i+1].level)时,您是在x 的范围之外进行比较。因为如果i == x.size() 那么x[i+1] &gt; x.size()

    我建议将您的循环更改为在i&lt;(x.size())-1; 而不是i&lt;=(x.size()); 终止

    【讨论】:

    • i
    • @KennyCason 没有什么比周一早上更能让我忘记数组从索引 0 开始的了
    • 呵呵。对我来说,几乎每天早上都有这种感觉:P
    【解决方案4】:

    正如其他人所说,问题在于这段代码:

        for (int i=0; i<=(x.size()); i++)
        {
            //if the level in the first is greater than the level in the next
            if(x[i].level > x[i+1].level)//I get a fatal error here when it tries to compare 
                                         //the iterator with 1 that's outside its range
    

    std::vector 可以按 0 到 size() - 1 的值(包括端点)来索引。因此,对于基本的vector 循环,您应该改为这样做

    for (int i = 0; i < x.size(); i++) {
    

    但是,在下一行代码中,您检查元素 i + 1,因此您应该这样做

    for (int i = 0; i < x.size() - 1; i++) {
    

    但是,因为 x.size() 是无符号的,如果 x 为空,那么 x.size() - 1 将是一个非常大的数字(在 32 位机器上为 2^32 - 1)。所以你应该为此调整逻辑。此外,比较有符号值(如int i 与无符号值(如x.size() - 1)可能会生成编译器警告(如果您尚未打开所有此类编译器警告,则应打开),因此将i 更改为@ 987654333@或size_t

    for (size_t i = 0; i + 1 < x.size(); i++) {
    

    最后,与其编写自己的冒泡排序,不如使用std::sortstd::sort 对于其他 C++ 开发人员来说更快、更熟悉。这是使用std::sort 的(未经测试的)示例:

    bool CompareByLevel(const Fighter& a, const Fighter& b) {
        return a.level < b.level;
    }
    
    sort(x.begin(), x.end(), CompareByLevel);
    

    其他 cmets:如果您有兴趣了解有关 C++ 的更多信息,这里有一些其他 cmets 可能会有所帮助。

    inputFile >> line;
    

    此语句实际上将单个空格或换行符分隔的单词读入line。如果这就是您想要做的,那么您选择的变量名 (line) 不会传达这一点。您可能希望能够在战士的名字中使用空格。要阅读整行,请使用:(请参阅 here 以供参考。)

    getline(inputFile, line);
    

    getEnemiesprintFightersortFighters 应该是 static 方法,因为它们不需要 Fighter 的特定实例来操作。 (现在,因为它们不是静态方法,所以您必须创建 Fighter 的 enemy 实例才能调用这些方法,即使这些方法都没有与 enemy 做任何事情。)

    C++ 允许您在堆栈上创建变量,而不是动态分配它们。换句话说,而不是说

    Fighter * temp = new Fighter;
    

    只是说

    Fighter temp;
    

    如果您不需要动态分配,这会更快更简单。

    最后,C++ 将为您创建复制类的所有成员的赋值运算符。所以你可以简单地写

    temp = x[i];
    

    而不是手动将 x 的每个成员分配给 temp。使用赋值运算符更加健壮,因为如果您以后将成员添加到 Fighter,它将继续工作。

    希望这会有所帮助。

    【讨论】:

    • 是的......这些似乎对我的程序没有任何帮助。
    【解决方案5】:

    您已经获得了一些关于如何修复该循环的建议。我的建议是消除它并改用std::sort

    虽然我们正在处理无法正确终止的循环,但可能还值得一提(getEnemies()):

        while(!inputFile.eof())
        {
            std::string line;
            inputFile >> line;
            if (line == "<fighter>")
            {
        // ...
    

    这也坏了。为了让循环正确终止,您需要读取数据,然后检查读取是否成功:

    std::string line;
    
    while (inputFile >> line) {
        if (line == "<fighter>") {
             // ...
    

    可能还值得注意的是,这段代码非常脆弱——仅举一个例子,例如:&lt;fighter&gt;fighter1&lt;/fighter&gt;被正确读取(它需要&lt;fighter&gt; 前后至少有一个空格,以将其作为单个字符串读取)。

    【讨论】:

    • 自己做算法的原因是为了练习自己的编程逻辑。对于最后一段,您是说我应该在“”之前和之后添加一个实际的空格吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    • 2020-02-10
    • 2018-09-30
    相关资源
    最近更新 更多