Filling array, not working correctly

Hi all. I wrote a Simon game, and wanted to save the top 10 scores. I was working right, until I decided I wanted to still be able to read the file if someone enters a name containing spaces. Now, the results aren't right. Could sure use some help, or pointing in the right direction. The routine is..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void FillScoreList(string Simon_Names[], int Simon_Scores[])
{

	ifstream Simon_HiScores("Simon_Data.txt");

	if (Simon_HiScores.is_open())
	{
		for( int x=0;x<10;x++)
		{
			//Simon_HiScores >> Simon_Names[x] >> Simon_Scores[x]; // This worked before trying 
                                                                               // to read names with getline
			getline(Simon_HiScores,Simon_Names[x]);
			Simon_HiScores >> Simon_Scores[x];
		}
	}
	else // Create file and fill arrays with default data 
	{
		ofstream Simon_HiScores("Simon_Data.txt");
		for( int x=0;x<10;x++)
		{
			Simon_HiScores << "Nobody" << endl << 0 << endl;
			Simon_Names[x] = "Nobody";
			Simon_Scores[x] = 0;

		}
		Simon_HiScores.close();
	}
}


Even without trying to read names with spaces, I'm getting
1
2
3
4
5
dad 1
0
340176
0
... either  a long number or a zero. No names

Last edited on
Is the format of your file something like?

dad 1
fred flintstone 2
mickey mouse 3
...

The problem is with

1
2
			getline(Simon_HiScores,Simon_Names[x]);
			Simon_HiScores >> Simon_Scores[x];


Is that getline reads the whole line into the string (e.g. "dad 1")

Then operator>> tries to extract an int value from the next line, but it finds a name (here, "fred"), which it cannot read into an int, so it puts the stream into a fail state.

As a result of this, all subsequent reads will also fail. The values you are printing out are just random data in your buffer (if you initialize it to zero you should have just blanks for the names and 0 for the scores).

One solution is to read the names into Simon_Names and then use assorted string methods to find, remove and convert the score, and store it in Simon_Scores (istreamstream comes from <sstream>). Like this (not so nice...):

1
2
3
4
5
6
			getline(Simon_HiScores,Simon_Names[x]);
			unsigned pos = Simon_Names[x].rfind(' '); // find last space
			string temp = Simon_Names[x].substr(pos + 1); // copy from after space to temp
			Simon_Names[x] = Simon_Names[x].substr(0, pos); // // remove last space onwards
			istringstream iss(temp); // use number string to init stringstream
			iss >> Simon_Scores[x]; // extract int 


Note that this code would not remove extra spaces. If you had three spaces between fred flintsone and the score, the name string would end up 2 space, i.e. "fred flintstone ". As your program writes and reads the file, this might not be an issue for you.

But another possibility is to use a different delimiter between the name and the scores, like a colon, which probably more sense here, as it requires less code.

dad:1
fred flintstone:2
mickey mouse:3
...

Then you can use

1
2
3
			getline(Simon_HiScores,Simon_Names[x],':'); // read until :
			Simon_HiScores >> Simon_Scores[x]; // read an int
			Simon_HiScores.ignore(1024, '\n'); // skip rest of line 


The ignore skips anything after the number until the end of the line, so that getline reads from the start of the next line. If you don't do this, getline will read everything from the first non-whitespace char if finds after the last number, up until the next :, endcluding the new line character, '\n'. So the second name would be (in C++ form) "\nfred flintstone" rather than "fred flintstone".

For future reference, mixing up formatted (extraction using operator>>) and unformatted (getline, get, ...) read operations can sometimes confuse istream/ifstream, so you might always get away with the most obvious "solution".

Andy
Last edited on
@andywestken


Is the format of your file something like?

dad 1
fred flintstone 2
mickey mouse 3
...


No. The file is created in the second part of the function if the file is not initially found. A name', "Nobody", on one line, then a zero, name , then zero, etc., as shown in the code.

1
2
3
4
5
6
7
ofstream Simon_HiScores("Simon_Data.txt");
	for( int x=0;x<10;x++)
	{
		Simon_HiScores << "Nobody" << endl << 0 << endl; // Creates the file 
		Simon_Names[x] = "Nobody"; // Fills the array
		Simon_Scores[x] = 0; // Puts a zero in Simon_Scores array
	}


I like the way you showed me, so I changed my code to that, and changed the creation of the file to match.
1
2
3
4
5
6
ofstream Simon_HiScores("Simon_Data.txt");
		for( int x=0;x<10;x++)
		{
			Simon_HiScores << "Nobody:" << Simon_Scores[x] << endl;
		}
		Simon_HiScores.close();


Works great now. Thanks for the help.
A name', "Nobody", on one line, then a zero, name , then zero, etc., as shown in the code.

Oops! Should have read more closely.

However, the reason it went wrong and the fix for your orig format are very similar to the second solution I gave before:

It goes wrongs as:

- the first getline reads the first name ok - "dad" - from the first line in your file
- the first operator>> reads the first number ok, on the second line of the file, but not the '\n' char
- the next getline reads up to the end of the current line, which is still the second line with the number on, so it reads nothing for the second name
- the second operator>> tries to extract the beginning of the second line in your file, which is not a valid number, so the stream is put into a fail state

After which nothing gets read.

istream::ignore also fixes the problem, but the getline call can be left as you originally hed it:

1
2
3
			getline(Simon_HiScores,Simon_Names[x]);
			Simon_HiScores >> Simon_Scores[x];
			Simon_HiScores.ignore(1024, '\n');


Andy
Last edited on
@andywestken

Thanks for the explanation as to why my way was not working. It had been driving me nuts trying to figure out why it started reading ok, then on the next line of the array, Simon_Names[1], it was blank, and the rest was screwed up. I liked the delimiter factor you showed, and it worked beautifully, so I'll leave it that way.

I do learn a lot using this site, and from the people, like yourself, that extend their knowledge and reasoning, to me. My thanks again for the great help.
Topic archived. No new replies allowed.