-
file i/o help
I am reading data from a file which I store in a linked list. However, for some reason when reading the list
I get an extra "node".
Here is my code.
Code:
// while not the end of the files keep reading
while(!sin.eof()) {
sin >> nextChar;
temp->idNumber = nextChar;
sin >> nextChar;
temp->LastName = nextChar;
sin >> nextChar;
temp->FirstName = nextChar;
sin >> nextChar;
temp->Major = nextChar;
sin >> nextChar;
temp->Class = nextChar;
InsertTail(temp); // insert the node
count++;
}
The file I read is 10 lines long. It seems that the
last element in the file fills an extra node up. So count prints 11 instead of 10.
I am sure the above code is the problem. Any
help would be great thanks in advance.
-
You will probably have to get your hands dirty and use the debugger. If you havent used one maybe somebody can get you started. What is the OS, and what compiler are you using?
-
Sure.
The EOF flag is not turned "on" until after the last character of the file is read, hence, your 'problem'. In short, your WHILE loop is going through one additional iteration accounting for 'count' going to 11 vice 10.
Try
This will account for all of the "flags" rather than testing for just EOF, i.e. good, bad, fail, eof.
-Skipper
-
I am using SunOS 5.8 with g++ 2.95.3. I have also tried to get it to work on a FreeBSD box. Would it help if I posted the full code (quite long) ?
Thanks.
-
I tried the while(sin) {} it still is doing it. I think it may be the file. The thing is, this is the one I have to use for the project. :(. Here is the full code
Code:
void LList::read(string &infile) {
REDO: // in the case where the file does not exist
// we will repeatly jump to this local to try again
ifstream sin; // create an instream
sin.open(infile.c_str(), ios::in); // open the file
// if the file can not be opened exit
if(sin.fail()) {
// print the error
cerr << endl << "*** ERROR: Can not open " << infile <<
" for reading." << endl;
// call getName and correct the mistake
getName(infile);
goto REDO; // jump back up to open
}
string nextChar; // hold string from sin
#ifdef g++good
// NOTE: since the version of g++ is unpatched, nothrow can not be used.
DATA *temp = new (nothrow) DATA;
if(temp == NULL) {
cerr << "Could not allocate memory. Consider closing some " <<
"applications.\n";
exit(1);
}
#else
// create a new instance of the DATA class (a node)
DATA *temp = new DATA; // alternative form
#endif
// while not the end of the files keep reading
while(sin) {
// NOTE: All data is assumed to be valid from the file
// so no type checking is needed.
sin >> nextChar;
temp->idNumber = nextChar;
sin >> nextChar;
temp->LastName = nextChar;
sin >> nextChar;
temp->FirstName = nextChar;
sin >> nextChar;
temp->Major = nextChar;
sin >> nextChar;
temp->Class = nextChar;
InsertTail(temp); // insert the node at the end of the list
count++; // add number to list
}
delete temp; // free temp
sin.close(); // close the file
} // end method read
See anything wrong with that?
-
For starters, why don't you consider writing an overload for operator>>. I suspect that the stream is invalid after you check it but before you have read in a whole object. The half filled element would then be the 11th entry. Maybe your file has a blank line at the end...
Code:
// helper function
void get(istream& s, std::string& str)
{
s>>str;
// check for a failed stream in the middle of reading a
// record: Maybe you can throw an exception or something
// here that you can catch in some outer while loop
if ( s.fail() ) // throw Some_Exception();
}
istream& operator>>(istream& s, DATA& d)
{
get(s,d.idNumber);
get(s,d.LastName);
get(s, d.FirstName);
get(s, d.Major);
get(s, d.Class);
return s;
}
int main()
{
// much code excluded...
DATA* data = new DATA();
try {
while(sin) {
sin>> *data;
InsertTail(data);
count++;
}
}
catch(...) {
// catch your exception here
}
return 0;
}
-
One possibility.
If your file was created as a char array rather than a pure 'string', there would be a trailing '\0' character, or characters. This, of course, would signify the end of the array, but would also account for an additional, if unwanted, character in your WHILE loop.
I'm starting to "reach" here myself, but it's a thought that you may want to pursue.
The logic is simple enough. You're reading more than you should be reading. The question is, "Why?"
-Skipper
-
Thanks for all the help guys.