-4

When the program enters in the if and then break, empty cout-s are printed again.

void Person::ShowRecords()
{
    std::ifstream data("Input.txt");

    while (true)
    {
        if (!data.good())
        {
            break;
        }

        Person person;
        data >> person;
        
        std::cout << "First Name: " << person.getFirstName() << "\n";
        std::cout << "Last Name: " << person.getLastName() << "\n";
        std::cout << "Phone number: " << person.getNumber() << "\n";
        std::cout << "EGN: " << person.getEGN() << "\n\n";
    }
}
Costantino Grana
  • 3,132
  • 1
  • 15
  • 35
  • 3
    related/dupe: https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons – NathanOliver Aug 04 '20 at 18:47
  • 4
    Essentially, you need to check the stream status _after_ `data >> person`, not _before_. – 1201ProgramAlarm Aug 04 '20 at 18:48
  • @1201ProgramAlarm thanks – Alexandar Zhelev Aug 04 '20 at 18:58
  • @AlexandarZhelev `while (true) { if (!data.good()) { break; } ... }` should be `while (data.good()) { ... }` or simply `while (data) { ... }` A better option is to move the declaration of `person` above the loop and then use `while (data >> person) { ... }` instead. – Remy Lebeau Aug 04 '20 at 19:01
  • @1201ProgramAlarm opening a file also sets the stream's state, so checking `good` (or `bad`) before checking `data >> person` is OK in this case. However, the state should also be checked *after* `>>` and *before* using `person`. – Remy Lebeau Aug 04 '20 at 19:03

1 Answers1

2

I really think that the most didactic way of tackling stream input is:

while (true) {
    // Read
    // Check (if fail then break)
    // Use
}

Notice the pattern: infinite loop with Read/Check/Use. Check is where we can exit the loop. First you read, than you check if the reading operation was successful or failed, than you can use the data or exit based on that.

Adapting this to your case:

void Person::ShowRecords()
{
    std::ifstream data("Input.txt");    
    while (true) {
        // Read
        Person person;
        data >> person;
        // Check
        if (!data) {
            break;
        }
        // Use          
        std::cout << "First Name: " << person.getFirstName() << "\n";
        std::cout << "Last Name: " << person.getLastName() << "\n";
        std::cout << "Phone number: " << person.getNumber() << "\n";
        std::cout << "EGN: " << person.getEGN() << "\n\n";
    }
}

The non didactic and probably more idiomatic way is:

void Person::ShowRecords()
{
    std::ifstream data("Input.txt");    
    Person person;
    while (data >> person) { // Read and, immediately after, Check
        std::cout << "First Name: " << person.getFirstName() << "\n"; // Use
        std::cout << "Last Name: " << person.getLastName() << "\n";
        std::cout << "Phone number: " << person.getNumber() << "\n";
        std::cout << "EGN: " << person.getEGN() << "\n\n";
    }
}
Costantino Grana
  • 3,132
  • 1
  • 15
  • 35