I'm at a loss (input/output)

I have an assignment that requires me to read names from one .txt file and grades from another and send the average(in letter grade) to an output .txt file. I'm still in the process of finishing the code but I cannot get any text to display in the output file (report.) The program creates the file without any issues but I think I'm screwing up somewhere with the strings. Apologies in advance for the messy 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
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>

using namespace std;

int main() {
	ifstream students("students.txt");
	ifstream grades("grades.txt");
	ofstream report("report.txt");

	string firstname;
	string lastname;

	int test1, test2, test3;
	double average;

	students.open("students.txt");
	grades.open("grades.txt");
	report.open("report.txt");
	
	students >> firstname >> lastname;
	grades >> test1 >> test2 >> test3;

	average = test1 + test2 + test3 / 3.0;

	report << "Student's Name" << " Student's Grade" << endl;
	report << lastname << "," << firstname << " " << average << endl;

	students.close();
	grades.close();
	report.close();
	return 0;
}
Last edited on
How many records do you have on
students.txt
?

I recommend Lines 10 to 12 would be,
1
2
3
	ifstream students;
	ifstream grades;
	ofstream report;


Also, for your two input tile, I would verify that it can open successfully. For instance,
1
2
3
4
       if (!students)
            // Could not open.
       else
           // Continue to compute info 
Last edited on
How about something like 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
36
#include <iostream>
#include <fstream>
// #include <iomanip>  // You're not currently using this
#include <string>

using namespace std;

int main() {

        ifstream students("students.txt");
        ifstream grades("grades.txt");
        ofstream report("report.txt");

        string firstname, lastname;

        int test1, test2, test3;
        double average;

        report << "Student's Name" << "\tStudent's Grade" << endl;

        while(students >> firstname >> lastname)
        {
        grades >> test1 >> test2 >> test3;

        average = (test1 + test2 + test3) / 3.0;

        report << lastname << "," << firstname << "\t" << average << endl;
        }

        students.close();
        grades.close();
        report.close();

return 0;
}

Students file (students.txt):
Daniel Forest
Michelle Wong
Derek Hass

Grades file (grades.txt):
98      21      21
87      23      77
86      54      98

Output (in report.txt):
Student's Name  Student's Grade
Forest,Daniel   46.6667
Wong,Michelle   62.3333
Hass,Derek      79.3333

.. and, yeah, good idea, as noted already, to verify that the files can be successfully opened, but I didn't put any code in there for that.
Last edited on
There were just two names in the input .txt. My problem was that I was opening the files twice. Do I need to use the header <iomanip> to align the output data in a format like this?
Student's Name        Student's Grade
Donnelly, Quintin     Teacher was far too easy
Nunez, Justin         A
My problem was that I was opening the files twice.


I am glad you figured it out.

Do I need to use the header <iomanip> to align the output data in a format like this?
Yes, I would strongly recommend to use the library.
I just modified that code a little, most notably changing:

average = test1 + test2 + test3 / 3.0;

to

average = (test1 + test2 + test3) / 3.0;

... otherwise your averages will be incorrect.

I also just used the tab character ("\t") to align the columns, but you'll have far better control by using <iomanip>.
Last edited on
Okay for the last part I have to use if statements to put their letter grade in the output file. I know how to do it I'm just unclear as to where I would put it in the code. Would it need to go inside the while statement?
So are you calculating their letter grade from their average score? ... or getting the letter grade from somewhere else?
I have to use if statements based on the typical U.S. grading scale like this

'A': grade >= 90

'B': 90 > grade >= 80

'C': 80 > grade >= 70

'D': 70 > grade >= 60

'F': grade < 60

And that cheesy "Teacher was too easy" message if the grade is >100
Well, you could do it like 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>

using namespace std;

int main() {

        ifstream students("students.txt");
        ifstream grades("grades.txt");
        ofstream report("report.txt");

        string firstname, lastname, letter_grade;

        int test1, test2, test3;
        double average;

        report << "Student's Name" << "\tStudent's Grade" << endl;

        while(students >> firstname >> lastname)
        {
        grades >> test1 >> test2 >> test3;

        average = (test1 + test2 + test3) / 3.0;

          if (average==100){
             letter_grade="Teacher too easy";
          }
          else if (average>=90){
             letter_grade="A";
          }
          else if (average>=80){
             letter_grade="B";
          }
          else if (average>=70){
             letter_grade="C";
          }
          else if (average>=60){
             letter_grade="D";
          }
          else {letter_grade="F";}

        report << lastname << "," << firstname << "\t" << average
               << " (" << letter_grade << ")" << endl;
        }

        students.close();
        grades.close();
        report.close();

return 0;
}


Output:
Student's Name  Student's Grade
Forest,Daniel   46.6667 (F)
Wong,Michelle   62.3333 (D)
Hass,Derek      79.3333 (C)

Ideally I think I'd want to put the calculation for the letter grade into a function which you call for each student, rather than have all those "if"s in the main loop, but I don't know if you've learned anything with functions yet.

Also, not quite sure if I got the numbers exactly right for the letter-grade calculation, but I'm sure you get the drift and can change it easily enough.

Things you should ideally still do:
(a) put code in to check that the files don't fail to open
(b) use features of <iomanip> to format the report output, rather than just use tabs

P.S. The code below shows why you needed to change the line which calculates the average:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

int main()
{
double average;
int a=10, b=20, c=30;

average= a + b + c / 3;
std::cout << average << std::endl;
// this gives average as 40, which is wrong

average= (a + b + c) / 3;
std::cout << average << std::endl;
// this gives average as 20, which is correct
}

Division has a higher order of precedence than addition, so in the first example the program first calculates c/3 (which is 10) and then adds it to a+b which comes to 40. In the second example, by putting a+b+c in parentheses, it adds them together first (which gets 60) and then divides the 60 by 3 to get 20.

Hope that helps. Good luck.
Last edited on
Topic archived. No new replies allowed.