Программа переходит в бесконечный цикл С++

Ниже приведена программа, в которой я перегрузил оператор ">>".

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

class Student{
    public :
        string name;
        string entry_no;
};

class Science : public Student{
    public :
    float marks;
    void create_file();
    void highest();

    friend istream& operator >> (istream& input, Science& stud);
};

istream& operator >> ( istream& input, Science& stud){
    input >> stud.name;
    input >> stud.entry_no;
    input >> stud.marks;
    return input;
}
void Science::create_file(){
    ifstream file_read;

    file_read.open("student.txt");

    ofstream file_write;
    file_write.open("science.txt");
    string line;

    while(!file_read.eof()){
        getline(file_read,line,'\n');

        if(line.find("Science") != string::npos){
            file_write << line;
            file_write << '\n';
        }
    }
}

class Art : public Student{
    public :
    string marks;
    void create_file();
    void highest();
    friend istream& operator >> (istream& input, Art& stud);
};

istream& operator >> ( istream& input, Art& stud){
    input >> stud.name;
    input >> stud.entry_no;
    input >> stud.marks;
    return input;
}

void Art::create_file(){
    ifstream file_read;

    file_read.open("student.txt");

    ofstream file_write;
    file_write.open("art.txt");
    string line;

    while(!file_read.eof()){
        getline(file_read,line,'\n');

        if(line.find("Art") != string::npos){
            file_write << line;
            file_write << '\n';
        }
    }
    file_read.close();
    file_write.close();
}

void find_marks(){

    string entry_no;
    cout << "Enter entry_no of the student to find marks " << endl;
    cin >> entry_no;

    ifstream file_read;
    file_read.open("science.txt");
    string stud_entry;
    Science stud;
    bool found = false;
    if(file_read.is_open()){
        cout << (file_read >> stud) << endl;
    while( file_read >> stud ){
        cout << "hi";
        if(!entry_no.compare(stud.entry_no)){
            cout << stud.marks << endl;
            found = true;
            break;
        }
    }
    }
    else
        cout << "error in openning"<< endl;

    if(!found)
        cout << "this student does not exist" << endl;
}

int main(){
    Science science_stud;
    Art art_stud;

    science_stud.create_file();
    art_stud.create_file();
    find_marks();   
    return 0;
}

Здесь цикл while в функции find_marks() переходит в бесконечный цикл, если entry_no не совпадает. Кто-нибудь может объяснить, почему это происходит?


person neel    schedule 04.11.2012    source источник
comment
Ваш цикл while должен быть while (file_read >> stud).   -  person chris    schedule 04.11.2012
comment
Я подозреваю, что вы получаете сообщение об ошибке при чтении вашего файла, но не eof. Можете ли вы привести небольшой пример файла science.txt, где он не работает?   -  person Vaughn Cato    schedule 04.11.2012


Ответы (1)


Тестирование на eof() действительно полезно только для того, чтобы определить, хотите ли вы напечатать ошибку, потому что предыдущее преобразование не удалось или нет. Это действительно плохое состояние цикла:

  1. Это не обязательно когда-либо достигнуто. Например, если преобразование в какой-то момент завершается неудачно, поток переходит в состояние сбоя, когда он отказывается извлекать дальнейшие символы до тех пор, пока состояние не будет очищено.
  2. Флаг std::ios_base::eofbit не устанавливается при достижении EOF (по крайней мере, его установка не гарантируется), но он гарантированно устанавливается только после попытки чтения за концом файла. Таким образом, последний набор данных, как правило, обрабатывается дважды.

Правильный способ — просто использовать преобразование в bool после чтения данных:

while (file >> whatever) {
    ...
}

Если в вашем руководстве по C++ вам рекомендовалось использовать eof(), вам, вероятно, следует сжечь его и посоветовать другим не покупать копию (им придется сжечь). Если ваш учитель сказал вам использовать eof() - ... ну, насколько я понимаю, сжигание людей вышло из моды. Вы должны, по крайней мере, сказать ему, что он не прав.

person Dietmar Kühl    schedule 04.11.2012
comment
Я использовал вышеуказанное условие, но в этом случае он никогда не входит в цикл - person neel; 04.11.2012
comment
@neel вы проверили, успешно ли был открыт файл? - person moooeeeep; 04.11.2012
comment
Если я использую eof, он входит в цикл - person neel; 04.11.2012
comment
@neel: это означает, что вы не предоставляете набор данных, соответствующий вашей попытке чтения! Вы не указали, к какому типу относятся члены вашего класса, но я рискну предположить, что name — это std::string, а entry_no — целое число. ... и, кроме того, я был бы готов поспорить, что ввод начинается примерно так: John Smith 17. В этом случае обратите внимание, что чтение name просто читает "John" и попытка прочитать "Smith" как целое число, которое, очевидно, терпит неудачу. Конечно, невозможность прочесть хотя бы один ввод подчеркивает, что использование eof() неправильно... - person Dietmar Kühl; 04.11.2012
comment
Я преобразовал name,entry_no и все отметки в строку, но все равно не работает - person neel; 04.11.2012
comment
Я проверил вывод файла file_read ›› stud, он возвращает 0. - person neel; 04.11.2012
comment
@neel: Может быть, вы можете поделиться [соответствующей частью] своего кода, начальной частью вашего ввода и убедиться, что файл действительно успешно открыт (std::ifstream in("somefile"); if (!in) { std::cout << "failed to open somefile\n"; }. В качестве альтернативы, проверьте каждую отдельную часть вашего ввода (т.е. в вашем операторе ввода) и отображать то, что он прочитал. В конце концов, часть обучения программированию — это обучение обнаружению проблем... - person Dietmar Kühl; 04.11.2012
comment
@neel: Да, если установлено std::ios_base::failbit (потому что потоку не удалось прочитать ввод декодирования или потому что его не удалось открыть), поток преобразуется в false (или 0, если вы не настроили двоичное форматирование для использования строк, используя, например, std::cout << std::boolalpha;). Вам нужно будет найти причину, по которой поток переходит в состояние сбоя. - person Dietmar Kühl; 04.11.2012
comment
давайте продолжим это обсуждение в чате - person neel; 04.11.2012