Loop with file input not ending properly

closed account (o9wX92yv)
I've got an input plain text file that I want to read in from, terminated by a newline character. The input is being stored in "Star" objects, which are stored in a linked list, and it all seems to be fine... except I keep getting an extra, blank entry at the very end.

I used similar code on a previous class assignment and just made a kludge that deleted the false entry at the end, but I'd like to get it right this time.

Here's what I have:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ifstream infile;

char temp[ENTRY_SZ];
Star* newEntry;
while (infile) //I'm assuming this is the crux of the problem
{
	infile.getline(temp,ENTRY_SZ, ',');
	newEntry = new Star(temp);
			
	infile.get();
	infile.getline(temp,ENTRY_SZ, ',');
	newEntry->SetTemperature(temp);

	// etc

	starList.AddLinkToBack(newEntry); //add fully filled-out Star object to the back of the linked list
}

infile.close();
infile.clear(ios_base::goodbit);


The file I'm reading from is formatted thusly:

1
2
3
4
5
Orionis, 33000, 30000, 18.0, 5.90
Spica, 22000, 8300, 10.5, 5.10
...
Becrux, 30000, 16000, 16, 5.7
					(ie: a blank line)


So, any recommendations? eof? changing to a do while loop? Some kind of index variable?
Last edited on
And what's wrong with deleting that extra blank entry? While a patchwork solution, sometimes it's the best one. >_>

Sadly we don't know enough about the format of the file versus the expected format of the file to really help you much beyond that.

-Albatross
closed account (o9wX92yv)
I've updated the original post with an example of the input file's format.

And what's wrong with deleting that extra blank entry?


Because of the constraints of the assignment, the linked list is a queue, and the only operations used are adding to back and removing from the front. If I wanted to remove the erroneous last-entered link, I'd have to copy over the entire list (-1) piecemeal.

There has to be a more elegant solution, I can't imagine every student doing this assignment has had to use that kind of awkward workaround.
Last edited on
The problem is a common one. That is, after each input operation,your program should be checking that the operation was successful.

For example:
1
2
3
4
5
6
7
8
9
10
while (infile)
{
    infile.getline(temp,ENTRY_SZ, ',');
    if (!infile) // did the getline succeed?
        break;   // no, exit the while loop.

    newEntry = new Star(temp);
			
    // etc.
}


Or carry out and test all of the inputs as part of the while condition.This way, you only enter the body of the loop when all the getlines were successful. I used a cout here purely for illustration. In your code you need to do something else with the results.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    ifstream infile("input.txt");

    char temp1[ENTRY_SZ];
    char temp2[ENTRY_SZ];
    char temp3[ENTRY_SZ];
    char temp4[ENTRY_SZ];
    char temp5[ENTRY_SZ];
    
    while (infile.getline(temp1,ENTRY_SZ, ',') 
        && infile.getline(temp2,ENTRY_SZ, ',')
        && infile.getline(temp3,ENTRY_SZ, ',')
        && infile.getline(temp4,ENTRY_SZ, ',')
        && infile.getline(temp5,ENTRY_SZ, '\n') ) 
    {
        cout << setw(15) << temp1  
             << setw(10) << temp2  
             << setw(10) << temp3  
             << setw(10) << temp4  
             << setw(10) << temp5 << endl;  
        

    }

Output:
        Orionis     33000     30000      18.0      5.90
          Spica     22000      8300      10.5      5.10
         Becrux     30000     16000        16       5.7


You might even do this,if your Star class has a suitable constructor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    char temp1[ENTRY_SZ];
    char temp2[ENTRY_SZ];
    char temp3[ENTRY_SZ];
    char temp4[ENTRY_SZ];
    char temp5[ENTRY_SZ];
    
    Star* newEntry;
    
    while (infile.getline(temp1,ENTRY_SZ, ',') 
        && infile.getline(temp2,ENTRY_SZ, ',')
        && infile.getline(temp3,ENTRY_SZ, ',')
        && infile.getline(temp4,ENTRY_SZ, ',')
        && infile.getline(temp5,ENTRY_SZ, '\n') ) 
    {
        int    a = atoi(temp2);
        int    b = atoi(temp3);
        double c = atof(temp4);
        double d = atof(temp5);
        
        newEntry = new Star(temp1,a, b, c, d);
        starList.AddLinkToBack(newEntry); 
    }
Last edited on
closed account (o9wX92yv)
Ah, thank you! The concept of checking for input failures within the loop really shouldn't have been so hard to figure out.

The infile.getline must have grabbed the "/n" at the end of the file and just used that as input, since it's not the eof marker, and then carried on with the loop. I was trying to come up with some way to use peek() or work with added variables, but just having checks all the way through would prevent both empty and partial entries from being added.

Thanks again!
Topic archived. No new replies allowed.