getline() is repeatedly reading the first line of my file
I don't know if anyone will see this in time, but I'll try... I am in an introductory c++ class (undergrad) and I have an assignment due for monday morning...(YES! I know I have procrastinated :), )
Ok. I have to read in student records in this form:
Adriana,Smith,692493955,50,43,52,86,74,83
Adrienne,Johnson,480562092,75,72,93,71,81,89
Bla, Bla, Bla
from a file (up to 200)and sort them and stuff.
I have managed to make all other necessary functions, but can't verify them.
I made a function that is supposed to open the file, read in each line and within each line read in each token and store them in a temporary array. This tempArr[9] goes and gets validated before getting put into the real array[9][200].
I have managed to open the file, read in the first line and tokenize it into an array, but when the while loop reiterates, it again reads in the first line of the file, thus when I print out the real array I get +/-200 times the first record.
I read and reread my manual, getline() info on cplusplus.com开发者_开发知识库, searched in forums and switched my code around a million times.
PLEEEEAAASSSSEEE HELP!
Here's the fn:
void getFile(std::string realArray[][200], const int ROW_SIZE)
{
std::string filename, token, line;
int positionLine(0);
int positionToken(0);
int row(0);
int numOfLine(0);
const int ROWS (9);
const int MAX_RECORDS (200);
std::string tempArray[ROWS];
std::cout << "Please enter the desired filename with it's extension:\t ";
std::cin >> filename;
const char *file=filename.c_str();
std::ifstream input(file, std::ios::in);
while (!input.is_open())
{
std::cout << "The file did not open correctly. \n\nPlease enter a valid filename.\n";
std::cin >> filename;
const char *file=filename.c_str();
std::ifstream input(file, std::ios::in);
}
while (input.good() && numOfLine < MAX_RECORDS)
{
getline (input,line);
std::istringstream inputss (line);
while (getline(inputss, token, ',') && row < ROWS )
{
tempArray[row] = token;
row++;
}
numOfLine++;
validateData (tempArray,ROWS , numOfLine);
storeData(tempArray, ROWS, realArray, ROW_SIZE, numOfLine);
}
if (numOfLine == MAX_RECORDS)
{
std::cout << "The maximum number of records to be read (" << MAX_RECORDS << ") has been reached.\n";
}
}
PS I'm working on visual studio 2010 and my file is *.dos
Oh, and I took out
using namespace std;
because it was giving : cout is ambiguous error.
THANKS N.
Where to start!!!!
Bad practice. One per line!
std::string filename, token, line;
These are un-used. Delete them.
int positionLine(0);
int positionToken(0);
Don't extract a pointer to a string into a new variable.
If filename is altered then file becomes invalid.
It is only safe to use when the result is passed into a function.
const char *file=filename.c_str();
std::ifstream input(file, std::ios::in);
Thus you should do it like this.
std::ifstream input(file.c_str());
Here. You are declaring a completely new variable input
. This variable has nothing to do with the other variable input
. This version is destroyed when it goes out of scope at the end of the while loop.
while (!input.is_open())
{
// <STUFF DELETED>
std::ifstream input(file, std::ios::in);
}
This is a very common mistake.
Testing for the good state here is (usually) wrong. This is because the normaly you want the loop to exit when you hit the end of file. But the last read actually reads up-to but not past the end of file and thus it does not trigger the EOF flag and the loop is re-entered. Then the next read will fail:
while (input.good() && numOfLine < MAX_RECORDS)
{
getline (input,line);
The better version is:
while (getline (input,line) && numOfLine < MAX_RECORDS)
{
Here you get it correct:
while (getline(inputss, token, ',') && row < ROWS )
{
Here you incrementing row to index into tempArray
. But I see no where that row is reset to 0.
tempArray[row] = token;
row++;
Edit:
Based on Bo's commoents below.
Technically there is nothing wrong with doing:
const char *file=filename.c_str();
std::ifstream input(file, std::ios::in);
Here the file
is used immediately and never used again. From experience though I find that by doing this you have introduced a new variable into the context that other feel free to re-use. Normally this is not a problem but this particular pointer can invisibly become invalid (if the filename object is modified then the file pointer can potentially become invalid).
This is a maintenance problem and is particularly dangerous when you have multiple developers modifying the code. If the variable file
is re-used later in the code by developer 'A' and developer 'B' then comes along and addes code that modifies variable filename
now you are in a situation that can be dangerous.
Thus it is always safer NOT to store pointers that can become invisibly invalid. Thus the only safe way to use them is as a parameters to functions.
std::ifstream input(filename.c_str(), std::ios::in);
Another situation that I came across recently was the same problem in a slightly different context:
QString path(<Some String>);
char* file = path.toLatin1().data();
readFile(file);
The problem here is that toLatin() returns an object of QByteArray. This object is returned by value and not assigned to any variable and thus is a temporary. Temporary objects are destroyed at the end of the expression so the method data() that returned a pointer to an internal part of the QByteArray has assigned to the variable file
a value that is invalid as soon as the ';' is hit.
The safe way to do this was to pass the result directly as a parameter to the function:
readFile(path.toLatin1().data());
My guess is you're not re-setting the value of row
... therefore when you increment row and it exceeds the value of ROWS
, you stop storing any new values inside of tempArray
. So you're reading the file just fine from getline()
, but you're not storing those new values in tempArray to be validated once row >= ROWS
.
Resetting the value of row
should do the trick. You also may want to, depending on how your validateData()
function works, pass it the value of row
rather than ROWS
so that you don't get data stored from the previous loop mixing in with the data read on the current loop if getline(inputss, token, ',')
returns an error and bails before you've read ROWS
amount of data.
Hope this helps,
Jason
精彩评论