Неустранимая ошибка приращения цикла - PullRequest
2 голосов
/ 16 августа 2010

В настоящее время я пытаюсь создать функцию, которая сортирует вектор, полный бойцов, в функции sortFighters в файле Fighter.cpp.Кажется, все правильно компилируется;Однако, когда он запускается, я получаю фатальную ошибку в одной из строк вышеупомянутого файла .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

My 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;
}

Ответы [ 5 ]

3 голосов
/ 16 августа 2010
    for (int i=0; i<=(x.size()); i++) 
    { 
        if(x[i].level > x[i+1].level)
        {

гм .. Размер () отсчитывается от 1. Индексы отсчитываются от 0. Итак, вы захотите сделать это i < x.size(), а не <=. Но , в следующей строке вы говорите x[i+1], поэтому i не может даже добраться до последнего элемента, он должен остановить его до этого:

    for (int i=0; i < x.size()-1; i++) 
2 голосов
/ 16 августа 2010

Вы получили несколько советов о том, как исправить этот цикл. Мой совет - устранить это и использовать вместо него std::sort.

Хотя мы имеем дело с циклами, которые не завершаются правильно, тем не менее, вероятно, также стоит упомянуть еще одну (в getEnemies()):

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

Это тоже сломано. Для правильного завершения цикла необходимо прочитать данные, а затем проверить, успешно ли выполнено чтение:

std::string line;

while (inputFile >> line) {
    if (line == "<fighter>") {
         // ...

Вероятно, также стоит отметить, что этот код довольно хрупок - только для одного примера, например: <fighter>fighter1</fighter> будет не прочитан правильно (для требуется хотя бы один пробел до и после <fighter>, чтобы прочитать его как одну строку).

0 голосов
/ 16 августа 2010

Проблема, как уже говорили другие, заключается в следующем разделе кода:

    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

A 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 будет очень большим числом (2 ^ 32 - 1 на 32-разрядной машине). Таким образом, вы должны настроить логику для этого. Кроме того, сравнение значений со знаком (например, int i и значений без знака (например, x.size() - 1) может генерировать предупреждения компилятора (вы должны включить все такие предупреждения компилятора, если вы этого еще не сделали), поэтому измените i на unsigned или size_t:

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

Наконец, вместо того, чтобы кодировать свою собственную сортировку пузырьков, лучше использовать std::sort. std::sort быстрее и более знаком для других разработчиков C ++. Вот (непроверенный) пример использования std::sort:

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

sort(x.begin(), x.end(), CompareByLevel);

Другие комментарии: Если вам интересно узнать больше о C ++, вот несколько других комментариев, которые могут помочь.

inputFile >> line;

Это утверждение фактически читает одно слово, разделенное пробелами или символом новой строки, в line. Если это то, что вы пытаетесь сделать, то ваш выбор имени переменной (line) не говорит об этом. И вы можете захотеть использовать пробелы в именах бойцов. Чтобы прочитать всю строку, используйте это: (См. здесь для справки.)

getline(inputFile, line);

getEnemies, printFighter и sortFighters должны быть методами static, так как им не требуется конкретный экземпляр Fighter для работы. (Прямо сейчас, поскольку они не являются статическими методами, вы должны создать enemy экземпляр Fighter для вызова этих методов, даже если ни один из этих методов ничего не делает с enemy.)

C ++ позволяет создавать переменные в стеке вместо их динамического распределения. Другими словами, вместо того, чтобы говорить

Fighter * temp = new Fighter;

просто скажи

Fighter temp;

Это быстрее и проще, если вам не нужно динамическое распределение.

Наконец, C ++ создаст для вас операторы присваивания, которые будут копировать всех членов класса. Так что вы можете просто написать

temp = x[i];

вместо того, чтобы вручную присваивать каждому члену x значение temp. Использование оператора присваивания более надежно, так как оно продолжит работать в будущем, если вы позже добавите членов к Fighter.

Надеюсь, это поможет.

0 голосов
/ 16 августа 2010

Ваша проблема с этим циклом:

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<=(x.size()), это означает, что когда вы выполняете сравнение (x[i+1].level), которое нарушает программу, вы сравниваете за пределами x. Потому что если i == x.size(), то x[i+1] > x.size()

Я рекомендую изменить цикл так, чтобы он заканчивался на i<(x.size())-1; вместо i<=(x.size());

0 голосов
/ 16 августа 2010

Попробуйте изменить цикл for на

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

Таким образом, x[i+1] никогда не выходит за пределы
Вы пытались получить доступ к памяти, которая не была выделена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...