streaming with 'unget' problem

Having trouble with a fill-in the ... practice problem from my online book.

So the problem states:
Suppose we wish to read student data in the form
Jane Lee 100 98 97 100
Aaron X. Schmidt 37 42 49 54
Frank von Tardy 2 3 10 7
...
There is no need to use getline. Instead, use one while loop to process all of the lines in the file. Inside that loop, use two smaller loops: the first to read the name, and the second to add up the scores for that student. To read the name, use get to read until you encounter a digit, adding each character to the student’s name. To add the scores, write a second loop that processes the rest of the line. Use the one-character look-ahead technique from Section 8.2.2 to read and sum the numbers.
Print the name and total score for each student.


and the code they want you to fill in the rest 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
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
   cout << "Input file: " << endl;
   string input_file_name;
   cin >> input_file_name;

   ifstream in;
   in.open(input_file_name);

   char ch;
   while (in.get(ch))
   {
      // Add the characters before the first digit
      // to the student's name.
      string student = "";
      while (cin && !isdigit(ch))
      {
         student = student + ch;
         in.get(ch);
      }
      student = student.substr(0, student.length() - 1); // remove space at end
      
      int total = 0;
      // Add all of the numbers in the rest of the line.
      // Use the one-character look-ahead from Section 8.2.2
      // Stop when the last character read is a '\n'
      . . .
      
      cout << student << ": " << total << endl;
   }
   
   return 0;
}



This is what i filled in, and for some reason it seems to go into a never ending loop after the first main loop executes. I'm not sure why that is, when it goes back to the main loop i can tell it uses the newline character, but just freezes after.

Here is my 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
 #include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
   cout << "Input file: " << endl;
   string input_file_name;
   cin >> input_file_name;

   ifstream in;
   in.open(input_file_name);

   char ch;
   while (in.get(ch))
   {
      // Add the characters before the first digit
      // to the student's name.
      string student = "";
      while (cin && !isdigit(ch))
      {
         student = student + ch;
         in.get(ch);
      }
      student = student.substr(0, student.length() - 1); // remove space at end
      
      int total = 0;
      // Add all of the numbers in the rest of the line.
      // Use the one-character look-ahead from Section 8.2.2
      // Stop when the last character read is a '\n'
      int num = 0;
      while (ch != '\n')
      {
          if (isdigit(ch))
          {
              in.unget();
              in >> num;
              total = total + num;
          }
          in.get(ch);
      }
      in.unget();
      
      cout << student << ": " << total << endl;
   }
   
   return 0;
}


Last edited on
also forgot to ask, why in their code is the second loop have "cin" in its condition?
If this is for personal practice, I'd recommend finding different practice problems. Taking in data like shown should not have to be this drawn out and complicated. .get() and .unget() I feel are almost being abused here, misused.

The problem says, "There is no need to use getline." However, getline with stringstreams would be much easier logic than this.


The reason your code "freezes" is because you've coded an infinite loop. After your inner lowest while loop you use in.unget() (line 43). The character you unget is always going to be '\n', the new line character. And then it goes back to the main loop, uses .get to take the '\n' back in, then your next while loop just infinitely loops since '\n' isn't a digit.


also forgot to ask, why in their code is the second loop have "cin" in its condition?

It seems to be a typo. It should instead be "in" not "cin":

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
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
	ifstream in;
	in.open("file.txt");

	char ch;
	while (in.get(ch))// && !in.eof())
	{
		// Add the characters before the first digit
		// to the student's name.
		string student = "";
		while (in && !isdigit(ch)) //in not cin
		{
			student = student + ch;
			in.get(ch);
		}
		student = student.substr(0, student.length() - 1); // remove space at end

		int total = 0;
		// Add all of the numbers in the rest of the line.
		// Use the one-character look-ahead from Section 8.2.2
		// Stop when the last character read is a '\n'
		int num = 0;
		while (ch != '\n' && !in.eof())
		{
			if (isdigit(ch))
			{
				in.unget();
				in >> num;
				total = total + num;
			}
			in.get(ch);
		}
	//	in.unget();

		cout << student << ": " << total << endl;
	}

	return 0;
}
Last edited on
thank you, i noticed that allot of these exercises/problems have you do thing in a much more complex way then necessary as-well. not sure of there is a teaching method to this or if they just like to make it harder then it has to be lol.
there are a mix of ancient exercises from before the language had some features, coupled with teachers who believe you should know how to do it yourself just in case (eg, say you get a job later coding in C, which requires hands-on low level coding to do such things), and a dash of 'because you can do this using the language tools, its harder to find code to do it by hand, eg cheat'. And probably other reasons.

If I were teaching I would want you to do something like this using c++ tools. depending on the level of the students and all, I may have them do a few exercises twice, one with, and once without, the c++ tools, though. You need a little low level experience so you see how to do stuff hands-on: it helps 2 things. First, you can do it yourself in another language, and second, you get feel for how much work the c++ tools do for you and can watch out for hidden performance hits where a simple statement invokes a hefty loop /performance penalty that you otherwise might not have thought about.
Topic archived. No new replies allowed.