Sentinel Value Controlled Loops

I'm having issues figuring out a program I need to write. I can't figure out exactly how to start it and I'm not even sure I'm on the right track any help would be appreciated. I need to use a sentinel controlled loop to display the data. I believe I would use a sentinel value of -1 due to the content of the text file but I'm not sure of the steps to get there. Yes, I know the homework policy here, please read my note at the end of the page.

The program is described as follows.
Students in a self-paced course must take 10 quizzes. Each quiz is worth up to 12 points. A file named scoreData.txt contains a student’s first and last name initials, followed by their quiz scores so far, followed by a -1 sentinel value. The output should be as follows:
Name 1 2 3 4 5 6 7 8 9 10 Low Avg
A.A. 5 11 9 5 8 5 3 3 7.2
R.D. 11 2 3 12 8 11 9 2 9.0
J.E. 10 N/A 10.0
K.H. 4 11 5 4 6 8 2 6 11 5 2 6.7
G.M. 10 1 1 9 3 1 5.8
S.O. 3 1 6 1 4.5

The ScoreData.txt file is as follows:
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
A A
5
11
9
5
8
5
3
-1
R D
11
2
3
12
8
11
9
-1
J E
10
-1
K H
4
11
5
4
6
8
2
6
11
5
-1
G M
10
1
1
9
3
-1
S O
3
1
6
-1


Here is what I have right now:
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
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int main()
{
	ifstream gradeFile;						//Input filestream object named gradeFile, associate it with ScoreData.txt and attempt to open
 	gradeFile.open("ScoreData.txt");
  if(gradeFile.fail())
  {	
	  cout << "File not found. Program terminated." << endl;
	  return 1;
  }
  //Begin reading date from ScoreData.txt
	double score;
	char grade;

	while(!gradeFile.eof())
	{
		gradeFile >> score >> grade;
		cout << setw(20) << score << setw(20) << grade << endl;
	}
  gradeFile.close();

	return 0;
}


Final note: As you can probably tell this is part of a homework assignment. I know the policy on that here and I'm NOT just looking for an answer.

If someone could help me get the program to the point that it will output this:
1
2
A.A. 5 11 9 5 8 5 3
First Student Processed.

Then I will take it from there.
Last edited on
Alright, so for each student entry, you will need to do:
(1) 2 reads extracting chars (this will get the initials)
(2) keep reading ints until you reach a -1. Process each grade that's not a -1.

So, here's an outline:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(!gradeFile.eof())
{
    //1. read first initial
    //2. read second initial

    //3. print the initials

    //in another loop, do:

    //4. read a grade
    //5. if it's not -1, process it (print it, update the low value, update the sum and number of grades)

    //6. print the statistics (low, mean)
}
Ok thanks, here is what I have now. It's closer but still not correct. I get an uninitialized local variable error off of the "score" variable and it prints the first line "A.A. 5 11 9 5 8 5 3" correctly however it doesn't stop at the -1 and just spits out every other value in the text file in a long string... What am I doing wrong?

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
29
30
31
32
33
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int main()
{
	ifstream gradeFile;						//Input filestream object named gradeFile, associate it with ScoreData.txt and attempt to open
 	gradeFile.open("ScoreData.txt");
  if(gradeFile.fail())
  {	
	  cout << "File not found. Program terminated." << endl;
	  return 1;
  }
  //Begin reading date from ScoreData.txt
	char initial1;
	char initial2;
	int score;

	while(!gradeFile.eof())
	{
		gradeFile >> initial1 >> initial2;
		cout << initial1 << "." << initial2 << ".";
		while(score != -1)
		{
			gradeFile >> score;
			cout << setw(3) << score;
		}
	}
  gradeFile.close();
  cout << "\nFirst Student Processed." << endl;
	return 0;
}


Note that at this point my main goal is to get to the point that the program prints out
1
2
A.A. 5 11 9 5 8 5 3
First Student Processed.


I like coding in small steps so I can think about how each step is working.
Last edited on
You haven't given score a value before the while loop. You could read a score before the loop, then in the loop, process and read another score. Or, you could change the loop to a do {} while loop to save the trouble.
Ok I changed it to a DoWhile loop as shown here:

1
2
3
4
5
6
		do
		{
			gradeFile >> score;
			cout << setw(3) << score;
		}
		while(score != -1);


That fixed the uninitialized local variable.

It appears that the initial1 and initial2 variables are also grabbing all of the other values in the text file including the numbers and printing them out before the do {} while loop executes. This seems to be why I get a long string of all the information in the text file after the initial A.A. 5 11 9 5 8 5 3 output. Why is that?
Are you sure that's what happening? Because, given the logic, you print out "\nFirst Student Processed." after the entire file has been read.
Hmm... Well when I comment out the do {} while loop running the program outputs this:

1
2
3
A.A.5.1.1.9.5.8.5.3.-.1.R.D.1.1.2.3.1.2.8.1.1.9.-.1.J.E.1.0.-.1.K.H.4.1.1.5.4.6.8.2.6.1.1.5.-.1.G.M.1.0.1.1.9.3.-.1.S.O.3.1.6.-.1.-.
First Student Processed.
Press any key to continue . . .


With the loop it outputs this:

1
2
3
4
A.A.  5 11  9  5  8  5  3 -1R.D. 11  2  3 12  8 11  9 -1J.E. 10 -1K.H.  4 11  5
 4  6  8  2  6 11  5 -1G.M. 10  1  1  9  3 -1S.O.  3  1  6 -1
First Student Processed.
Press any key to continue . . .


So it's the only conclusion I can draw right now.

It appears to be pulling all values in the text document for the initials and then looping the cout << initial1 << "." << initial2 << "."; until the eof
Last edited on
All the initials are appearing correctly with the periods, and all the scores are being printed with a width of 3 so it looks like it's reading everything correctly. If all you want is the first student, then you should comment out the while(!gradeFile.eof()) portion of the loop.

When you comment out the do {} while loop it's putting everything it reads into chars. Note how everything is delimited by periods (including the negative signs).
Last edited on
Ah, I see what your saying I think. I changed it up a bit and now it outputs this:


1
2
3
4
5
6
7
8
A.A.  5 11  9  5  8  5  3 -1
R.D. 11  2  3 12  8 11  9 -1
J.E. 10 -1
K.H.  4 11  5  4  6  8  2  6 11  5 -1
G.M. 10  1  1  9  3 -1
S.O.  3  1  6 -1
First Student Processed.
Press any key to continue . . .


More than I'm looking for right now but I suppose it's OK (I can comment out the loop to get just the first student but this is fine). What I'm wondering now is why does it output the -1? I'm trying to use that as the sentinel value.

Current code:

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
29
30
31
32
33
34
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int main()
{
	ifstream gradeFile;						//Input filestream object named gradeFile, associate it with ScoreData.txt and attempt to open
 	gradeFile.open("ScoreData.txt");
  if(gradeFile.fail())
  {	
	  cout << "File not found. Program terminated." << endl;
	  return 1;
  }
  //Begin reading date from ScoreData.txt
	char initial1;
	char initial2;
	int score;

	while(!gradeFile.eof())
	{
		gradeFile >> initial1 >> initial2; //Get initials from ScoreData.txt
		cout << "\n" << initial1 << "." << initial2 << "."; //Display initials
		do
		{
			gradeFile >> score; //Get score ints from ScoreData.txt
			cout << setw(3) << score; //Display scores
		}
		while(score != -1);
	}
  gradeFile.close();
  cout << "\nFirst Student Processed." << endl;
	return 0;
}
Last edited on
why does it output the -1?

Because you're not telling it not to. The check for -1 happens after you read the score and output it. You can simply check if(score != -1) before outputting it. If you change the loop back to a while loop, you won't have to do the if statement, but you will also have to read the score before the loop (as well as at the end). Either way is fine, here.
Ok I see. My code is now this:

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
29
30
31
32
33
34
35
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int main()
{
	ifstream gradeFile;						//Input filestream object named gradeFile, associate it with ScoreData.txt and attempt to open
 	gradeFile.open("ScoreData.txt");
  if(gradeFile.fail())
  {	
	  cout << "File not found. Program terminated." << endl;
	  return 1;
  }
  //Begin reading date from ScoreData.txt
	char initial1;
	char initial2;
	int score;

	//while(!gradeFile.eof())
	{
		gradeFile >> initial1 >> initial2; //Get initials from ScoreData.txt
		cout << "\n" << initial1 << "." << initial2 << "."; //Display initials
		do
		{
			gradeFile >> score; //Get score ints from ScoreData.txt
			if(score != -1)
			cout << setw(3) << score; //Display scores
		}
		while(score != -1);
	}
  gradeFile.close();
  cout << "\nFirst Student Processed." << endl;
	return 0;
}


And it is doing what I want it to for now. I'm going to step away from this for now and take a break. I'll be back if I have any more issues.

Thanks for all your help.
Ok, I'm back. I'm now trying to wrap up this project and can't get it to work correctly.

I can't get the averages to calculate correctly or align how it should, I also can't figure out how to drop the lowest value before calculating the average (which I need to do) the output looks like this:

1
2
3
4
5
6
7
8
9
Name     1    2    3    4    5    6    7    8    9    10   Low  Avg
A.A.     5    11   9    5    8    5    3    6.6
R.D.     11   2    3    12   8    11   9    7.3
J.E.     10   7.5
K.H.     4    11   5    4    6    8    2    6    11   5    7.0
G.M.     10   1    1    9    3    6.6
S.O.     3    1    6    6.3
All Student Processed.
Press any key to continue . . .


It needs to look like this:

1
2
3
4
5
6
7
Name 1  2  3  4  5  6  7  8  9  10    Low Avg
A.A. 5  11 9  5  8  5  3              3   7.2
R.D. 11 2  3  12 8  11 9              2   9.0
J.E. 10                               N/A 10.0
K.H. 4  11 5  4  6  8  2  6  11 5     2   6.7
G.M. 10 1  1  9  3                    1   5.8
S.O. 3  1  6                          1   4.5


Here is my current code:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int main()
{

	ifstream gradeFile;	
 	gradeFile.open("ScoreData.txt");

	if(gradeFile.fail())
	{	
		cout << "File not found. Program terminated." << endl;
		return 1;
	}
	
	char initial1;		// initial one
	char initial2;		// initial two
	int score;			// student's test scores
	int numscores = 0;
	int sum = 0;
	float average;
	int s = 1;
	int lowestscore = 0;
	int M = 20;

	cout << "Name     ";
	for(s; s <= 10; s++)
		cout << left << setw(5) << s;
		cout << left << setw(5) << "Low";
		cout << left << setw(5) << "Avg";
	
	while(!gradeFile.eof())
	{
		gradeFile >> initial1 >> initial2;
		cout << "\n" << initial1 << "." << initial2 << ".     ";
		
		do
		{
			gradeFile >> score;
			if(score != -1)
			{
			cout << left << setw(5) << score;
			sum += score;
			numscores++;
			}
		}
		while(score != -1);

		average = (float) (sum - lowestscore) / numscores;
		cout << left << setw(5) << fixed << setprecision(1) << average; 
	}
	
	//for(
	gradeFile.close();
	cout << "\nAll Student Processed." << endl;

	return 0;
}



As you can see I changed a lot with the help of a friend. I'm not sure if we got off track or if we are just missing something simple.

Any help is appreciated.

Thanks!
First things first, you have to actually compute the lowestscore per student. To do that, set it initially to some value higher than any possible score (or initialize it to the first score). Then, when you read a new score, if that score is lower than the lowestscore then update the lowestscore.

Also, since you take out the lowestscore you need to modify your average calculation. Namely, you need to use one less score (see the denominator).

For alignment of the output, the setw before printing the lowestscore is dependent on how many scores you've read. You need to do a minor calculation to find out this output width.
Last edited on
Ok I made some changes and still can't get it working how I need it to, I created a while loop for finding the lowest score however it just makes the program hang...

Also I need to use a for loop to put spaces where there are no grades in order to correct alignment, I'm just not sure how I would detect that there is no value for score in that field and fill it with blank space using a for loop.

Here is my current code:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int main()
{

	ifstream gradeFile;	
	gradeFile.open("ScoreData.txt"); // Open gradefile

	if(gradeFile.fail())
	{	
		cout << "File not found. Program terminated." << endl;
		return 1;
	}

	// Declare variables
	char initial1;		// initial one
	char initial2;		// initial two
	int score;			// student's test scores
	int numscores = 0;
	float average;
	int s = 1;
	const int min = 101;
	int lowestscore;
	int M = 20;
	lowestscore = min;
	int scorecount = 0;
	int sum = 0;

	cout << "Name     "; // Form header line
	for(s; s <= 10; s++)
	cout << left << setw(5) << s;
	cout << left << setw(5) << "Low";
	cout << left << setw(5) << "Avg";

	while(!gradeFile.eof())
	{
		gradeFile >> initial1 >> initial2; // Get initials from file
		cout << "\n" << initial1 << "." << initial2 << ".     ";

		do
		{
			gradeFile >> score; // Get grades from file
			if(score != -1)
			{
				cout << left << setw(5) << score;
				sum += score;
				numscores++;
			}

			while (scorecount < numscores)
			{
				// Determine if grade is lowest
				if (score < lowestscore)
				{
					lowestscore = score;
					scorecount++;
				}
			}
		}
		while(score != -1);

		average = (float) (sum - lowestscore) / (numscores - 1); // Determine average
		cout << left << setw(5) << fixed << setprecision(1) << average; 
	}

	gradeFile.close();
	cout << "\nAll Students Processed." << endl;

	return 0;
}
I created a while loop for finding the lowest score...

You don't need a while loop for this. After you read a valid score, you simply have to check it with the lowestscore and update it if need be.

Also I need to use a for loop to put spaces where there are no grades in order to correct alignment...

You don't need a for loop for this. You can use the numscores variable to figure out the last score. If the last score was 10, you only need to add 5 spaces to be aligned with Low (setw(5)). If the last score was 9, then you need to add 10 spaces (setw(10)), and so on.
Last edited on
Topic archived. No new replies allowed.