4

I'm trying to make my program read in data from a data (.dat) file (which is really just a text file). So of course I'm using the loop condition while(!file.eof()), but this is never returning true. Here's my function:

void Table::readIn(const char finput[]){
    std::ifstream file;

    file.open(finput);

    if (!file.is_open())
    {
        std::cout << "Cannot open " << finput << std::endl;
        return;
    }
    char key[100];
    file.get(key, 99, '\n');
    while (!file.eof())
    {
        stock * item = new stock;
        item->setTick(key);
        file.get(key, 99, '\n');
        item->setName(key);
        file.get(key, 99, '\n');
        item->setValue(atof(key));
        file.get(key, 99, '\n');
        item->setDate(key);
        file.get(key, 99, '\n');
        item->setYearReturn(atof(key));
        file.get(key, 99, '\n');
        addStock(item);
    }
}

and here's what's in my data file:

TSLA
Tesla Motors, Inc.
30160000000
November 6, 2015
13.1

I wish I could give you guys more information, but the fact that the program is looping through the while (!file.eof()) loop indefinitely is all I know about this issue.

Edit: I ran this through a debugger, with a break point at every line of the while loop. What I found is that the first get() call (before the while loop) sets key to the correct value, but every get() call after that sets key to "". I'm assuming this is because the program is never reading past first '\n' character in the file. Do you guys know how to fix this?

Edit 2: This question is different from: Why is iostream::eof inside a loop condition considered wrong? because I have to read in more than one line each time I run through my while loop.

Logan Kling
  • 549
  • 2
  • 4
  • 16
  • To start with, the `eofbit` flags isn't set until after you try to read from beyond the end of the file, which means your loop won't work as you expect it to . To continue, try to step through the code line by line in a debugger, your reading won't work as you expect it either. – Some programmer dude Nov 07 '15 at 07:52
  • 1
    @JoachimPileborg Okay, the first `get()` call (before the while loop) sets `key` to the correct value, but every `get()` call after that sets `key` to "". I'm assuming this is because the program is never reading past first '\n' character in the file. Do you know how I would fix this? – Logan Kling Nov 07 '15 at 08:00
  • Simplest solution? Use `std::string` and `std::getline` to read lines. – Some programmer dude Nov 07 '15 at 08:03
  • "So of course I'm using the loop condition while(!file.eof())" – which is incorrect… – The Paramagnetic Croissant Nov 07 '15 at 08:25
  • 1
    @LarryK - After you have solved the `file.get()` problem, `while (!file.eof())` is still wrong (even if this is not what you asked about). – Bo Persson Nov 07 '15 at 10:01

2 Answers2

3

The problem with your use of std::istream::get is that it doesn't consume the delimiter. It will work fine for the first call, but then the next call will immediately see the newline left over from the previous call, and not read anything.

If you want to read lines, either use std::istream::getline (if you persist on using character arrays) or std::getline with std::string which is what I recommend.


You also don't need explicit eof checks, instead rely on the fact that all functions returns (a reference to) the stream and that the streams can be used directly in conditions, so do e.g.

if (!std::getline(...))
    // end of file or error
Some programmer dude
  • 363,249
  • 31
  • 351
  • 550
0

You will have to replace this line while (!file.eof()) by

while (true)
    {
        /*code*/
        file.get(key, 99, '\n');
        if (file.eof()) { break; } // and similarly for other usages where you are reading the stream
        /*code*/
    }

Edit: Ok. Looks like your problem lies here, quoting from documentation of ifstream::get:

the next available input character c equals delim, as determined by Traits::eq(c, delim). This character is not extracted

So after each call to get your seek pointer is still pointing to the deliminator. So after the first call, get keeps encountering the newline character and hence returning you an empty data. You can either add a dummy read to consume that deliminator or even better use getline

bashrc
  • 4,426
  • 1
  • 18
  • 45