1

I've been trying to write a code to read from a file line by line:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream jin("Story.txt");
    // ins.open("Story.txt", ios::in);
    if (!jin)
    {
        cout << "File not opened" << endl;
        return 1;
    }
    else{
    char a[100];
    do
    {
        jin.getline(a, 100);
        cout << a << endl;
    } 
    while (!jin.eof());
    jin.close();
    return 0;
    }
}

However, on executing this program on Visual Studio Code on Windows, it behaves as infinite loop. Can someone tell what's wrong?

(I am sure that the file Story.txt exists, no doubt about that)

  • 1
    At first, please, don't use `while (!jin.eof())`. ([SO: Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/q/5605125/7478597)) Better: `while (jin.getline(a, 100)) cout << a << endl;`. – Scheff's Cat Apr 23 '21 at 10:16
  • I'm not sure about VS Code but I know this issue from Visual Studio: The binaries are built in to a separate directory. When debugging is started that directory is set as Current Directory by default. You have to edit the settings to change this. – Scheff's Cat Apr 23 '21 at 10:18
  • @Scheff Please elaborate – loveofprogramming Apr 23 '21 at 11:35

2 Answers2

1

jin.eof() will only return true if a eof-token is found, and this will not happend unless the file is open. That is what causing your infinite loop.

Then you would probably want something like this:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream jin{"Story.txt"};
    if (!jin)
    {
        cout << "File not opened" << endl;
        return 1;
    }
    for (std::string a; std::getline(jin, a);) { // Read every line
       cout << a << "\n";
    }
    // jin is closed when going out of scope so no need for close();
    return 0;
}
Lasersköld
  • 996
  • 5
  • 10
  • 1
    " jin.eof() will not react unless you have successfully opened a file and that is what causing your infinite loop." I couldn't get you, can you please clarify again – loveofprogramming Apr 23 '21 at 11:41
  • Changed formulation and added link to SO-answer that explains it more clearly. (From @Scheff's comment) – Lasersköld Apr 23 '21 at 12:06
  • 1
    The boolean operator does indeed return `true` if the file is opened correctly. `if(!jin)` is the idiomatic way of checking that it failed and since the answer is built on the wrong assumptions, it fails to explain the infinite loop and isn't helping. – Ted Lyngmo Apr 23 '21 at 12:16
1

When std::istream::getline has read 100-1 characters (without finding a newline,\n), it will set the failbit on the stream. This prevents further reading on the stream (unless you reset that state). It does however not set eofbit so you are now in a bit of a pickle. The failbit prevents further reading, and eof() returns false, because eofbit is not set - it will therefore loop indefinitely.

If at least one of the lines in Story.txt is longer than 99 chars, the above is what will happen.

The easiest way out is to use a std::string and std::getline instead:

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

int main() {
    std::ifstream jin("Story.txt");
    if(!jin) {
        std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
        return 1;
    }

    std::string a;
    while(std::getline(jin, a)) {
        std::cout << a << '\n';
    }
    return 0;
}

If you really do not want to use std::getline and std::string, you can, but it's much harder:

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>

int main() {
    std::ifstream jin("Story.txt");
    if(!jin) {
        std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
        return 1;
    }
 
    char a[100];
    while(true) {
        jin.getline(a, 100);
        std::cout << a; // output what we got

        if(jin) {
            // got a complete line, add a newline to the output
            std::cout << '\n';
        } else {
            // did not get a newline
            if(jin.eof()) break; // oh, the end of the file, break out

            // reset the failbit to continue reading the long line
            jin.clear();
        }
    }
}
Ted Lyngmo
  • 37,764
  • 5
  • 23
  • 50