Reading numbers from text and outputting average - c++

So I am working to read text from a file (line by line) and output the ID, average of 4 grades following the ID, and the letter grade. So the letter grade for any average grade of 50 or above is S, anything below 50 is a U, and 2 excused classes results in the letter grade I. (No S or U if more than or equal to 2 excused).
So lets say file has the numbers:
42 50 51 57 52
48 90 -1 60 -1
40 46 -1 59 45
47 50 -1 49 50
The output should look something like this:
ID=42 Avg=52.5 Grade=S
ID=48 Excused=2 Grade=I
ID=40 Avg=50.0 Grade=S
ID=47 Avg=49.7 Grade=U
Number of Grades of Type
S U I
2 1 1
This is the output I am receiving from my code
It is reading all the numbers, but i need it to read the first number as ID and following 4 numbers as grade.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream in;
ofstream results;
string filename;
char grade;
int S = 0, U = 0, I = 0, i = 0, ID, excused = 0, avg;
double allscores = 0;
cout << "Enter the name of the file that has the scores of students: " << endl;
cin >> filename;
cout << "Enter the number of scores for each student: " << endl;
cin >> ID;
in.open(filename);
results.open("results.txt");
if (in)
{
while (in >> ID)
{
int first = 0
for (i = 0; i<=4; i++)
{
if (first == -1)
excused++;
else
allscores += first;
}
if (first > 4)
{
avg = allscores / (4 - excused);
if (avg >= 50.0)
{
grade = 'S';
S++;
cout << "ID=" << ID << " Avg=" << avg << " Grade =" << grade << endl;
}
else
{
grade = 'U';
U++;
cout << "ID=" << ID << " Avg=" << avg << " Grade =" << grade << endl;
}
}
else
{
grade = 'I';
I++;
cout << "ID=" << ID << " Excused=" << excused << " Grade =" << grade << endl;
}
}
}
else
{
cout << "Couldn't open file\n";
}
cout << "Number of Grades of Type" << endl;
cout << "S " << "U " << "I" << endl;
cout << S << " " << U << " " << I << endl;
in.close();
results.close();
system("pause");
return 0;
}

Your variable int first=0 is not being assigned any value other than 0 in your code so the statement if(first>4) will always be false and result the output your are getting.
You can do something like this:
while (in >> ID)//this is supposed to get the ID of each student, in order for that to happen you need to read all the 4 scores inside this loop before coming here and reading the next ID,otherwise everything will read as an ID
{
int first = 0
excused=0;//you need to reset excused on every iteration
allscores=0;//you need to reset allscore on every iteration
for (i = 0; i<4; i++)
{//here you need to get all the 4 scores
in>>first;//get each score in first
if (first == -1)
excused++;
else
allscores += first;
}
if(excused<2)//instead of if(first>4)
...//do your calculation for average score
else
...//set the grade to 'I'...
}

Here is my final solution:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream in;
ofstream results;
string filename;
char grade;
int S = 0, U = 0, I = 0, i = 0, ID, excused = 0, avg;
double allscores = 0;
cout << "Enter the name of the file that has the scores of students: " << endl;
cin >> filename;
cout << "Enter the number of scores for each student: " << endl;
cin >> ID;
in.open(filename);
results.open("results.txt");
if (in)
{
while (in >> ID)
{
int first = 0;
excused = 0;
allscores = 0;
for (i = 0; i < 4; i++)
{
in >> first;
if (first == -1)
excused++;
else
allscores += first;
}
if (excused < 2)
{
avg = allscores / (4 - excused);
if (avg >= 50.0)
{
grade = 'S';
S++;
results << "ID=" << ID << " Avg=" << avg << " Grade =" << grade << endl;
}
else
{
grade = 'U';
U++;
results << "ID=" << ID << " Avg=" << avg << " Grade =" << grade << endl;
}
}
else
{
grade = 'I';
I++;
results << "ID=" << ID << " Excused=" << excused << " Grade =" << grade << endl;
}
}
}
else
{
cout << "Couldn't open file\n";
}
results << "Number of Grades of Type" << endl;
results << "S " << "U " << "I" << endl;
results << S << " " << U << " " << I << endl;
in.close();
results.close();
system("pause");
return 0;
}
After the code I have it output to a file named "results".
Thanks for the help. I guess my while loop was the biggest mistake.
Especially not adding in the in >> first portion.

Related

Why doesn't my while statement end?

I've created this program to calculate scores of peoples tests and count the number of grades. What i want to happen is that when the user enters "//" when the program asks "Enter student Name", the while statement should end, or that's what i assume should happen. What actually happens is that i type "//" then the program asks for the score, then the while statement ends. Why is this and what should i do to fix it?
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name, grade;
int score;
int count1 = 0;
int acount = 0;
int bcount = 0;
int ccount = 0;
int dcount = 0;
int fcount = 0;
while (name != "//") {
cout << "Enter Student Name \n";
cin >> name;
cout << "Enter Student Score \n";
cin >> score;
count1 += 1;
if (score >= 90) {
grade = "A";
acount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score >= 80) {
grade = "B";
bcount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score >= 70) {
grade = "C";
ccount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score >= 60) {
grade = "D";
dcount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score <= 59) {
grade = "F";
fcount += 1;
cout << name << " " << score << " " << grade << endl;
}
};
cout << "Summary Report \n" << "Total Students Count: " << count1 << endl;
cout << "A student count: " << acount << endl;
cout << "B student count: " << bcount << endl;
cout << "C student count: " << ccount << endl;
cout << "D student count: " << dcount << endl;
cout << "F student count: " << fcount << endl;
return 0;
}
Most of the things have been already said in the comments:
Your problem is, that you expect the loop to check its condition continuously, which it does not.
while(name != "//") // here the condition is evaluated
{
name = "//"; // here it is not
// the following code is executed, independent of the current name value
} // here the program jumps back to the loop condition, which is now false and it will not enter another time.
Like mentioned in the comments, a working alternative could be:
while(true)
{
std::cin >> name;
if(name == "//")
break;
else
evaluateScore();
}
Try this:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name, grade;
int score;
int count1 = 0;
int acount = 0;
int bcount = 0;
int ccount = 0;
int dcount = 0;
int fcount = 0;
while (true) { // keep running the loop
cout << "Enter Student Name \n";
cin >> name;
if(name == "//") // if "//" found, break the loop
break;
cout << "Enter Student Score \n";
cin >> score;
count1 += 1;
if (score >= 90) {
grade = "A";
acount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score >= 80) {
grade = "B";
bcount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score >= 70) {
grade = "C";
ccount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score >= 60) {
grade = "D";
dcount += 1;
cout << name << " " << score << " " << grade << endl;
}
else if (score <= 59) {
grade = "F";
fcount += 1;
cout << name << " " << score << " " << grade << endl;
}
};
cout << "Summary Report \n" << "Total Students Count: " << count1 << endl;
cout << "A student count: " << acount << endl;
cout << "B student count: " << bcount << endl;
cout << "C student count: " << ccount << endl;
cout << "D student count: " << dcount << endl;
cout << "F student count: " << fcount << endl;
return 0;
}

Saving all Inputs entered for display on cout - C++

I have looked in the forum but can't seem to find anything specific to what I need.
I am writing a program that asks the user to input a number of students. Depending on the number of students they enter they will then have to enter the students name and a series of 10 grades, or pressing 999 to cancel. The program will later have to display all students entered with their average grade. What I have now just overrides the previous inputs and displays the last one entered.
This is what I have so far:
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
int main() {
std::string teacherName = "";
std::string classDesignation ="";
int numStudents = 0;
std::string studentName = "";
double grade[10];
double averageGrade = 0.00;
char letterGrade;
std::cout << "Enter the teacher's name: ";
getline(std::cin, teacherName);
std::cout << "Enter the class designation: ";
getline(std::cin, classDesignation);
std::cout << "Enter the number of students ( 1 or more ): ";
std::cin >> numStudents;
std::cin.ignore();
for (int x = 0; x <= numStudents - 1; x++) {
std::cout << "Enter the student's name: ";
getline(std::cin, studentName);
for (int i = 0; i <= 9; i++) {
std::cout << "Enter grade from 0 - 100 or 999 to stop: ";
std::cin >> grade[i];
if (grade[i] == 999){
break;
}
averageGrade += grade[i];
if (averageGrade <= 59){
letterGrade = 'F';
}
if (averageGrade >= 60 || averageGrade <= 69){
letterGrade = 'D';
}
if (averageGrade >= 70 || averageGrade <= 79){
letterGrade = 'C';
}
if (averageGrade >= 80 || averageGrade <= 89){
letterGrade = 'B';
}
if (averageGrade > 90){
letterGrade = 'A';
}
}
}
std::cout << "Teacher: " << teacherName << std::endl;
std::cout << "Class: " << classDesignation << std::endl;
std::cout << "Student Name: " << studentName;
std::cout << std::setw(19) << "Average: " << averageGrade;
std::cout << " Grade: " << letterGrade << std::endl;
std::cout << "Student count: " << numStudents << std::endl;
std::cout << "Student average: " << std::endl;
std::cout << "A's: " << std::endl;
std::cout << "B's: " << std::endl;
std::cout << "C's: " << std::endl;
std::cout << "D's: " << std::endl;
std::cout << "F's: " << std::endl;
return 0;
}
Any tips?
Thank you!
#Hansel, here's what I think will work. We'll change this line to get what we want:
averageGrade += grade[i];
To:
//to declarations:
double averageGradeSum = 0.00;
//then change the line mentioned before to:
averageGradeSum += grade[i];
Then:
//if for some reason you're indexing starts at 1
averageGrade = averageGradeSum/i;
//if indexing starts at 0 like usual C++ use:
averageGrade = averageGradeSum/(i+1);
I'm not going to test this. It should make sense and if I screwed up the syntax it should be an easy google adventure to fix. Enjoy :)
From what I see, you can store them in associative vectors, one for the student name, and one for the average grade. You can also have a doubly linked list of student nodes which would look something like this:
struct student
{
std::string student_name;
int ave_grade;
// Head points to the previous student in the array.
// Tail points to the next student in the array.
student *head;
student *tail;
}
Declare a struct that everything hangs from to prevent memory leaks: student list_head; and each time you have an input, add a new node to the list.

c++ while loop from file with different data types

I have a file that includes this information:
Bev Powers
3
76 81 73
Chris Buroughs
5
88 90 79 81 84
Brent Mylus
2
79 81
I have a count controlled loop that will do the first 3 lines and use the information correctly but I am struggling with a loop that will reuse the the loop until all the information is displayed from the file regardless of how many golfers with matches are on the file. I am asking for pointers in the right direction, any assistance would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
ifstream inScores;
string filename;
string name;
int loopCount, matchScore;
int count = 1;
float mean = 0;
float adder = 0;
int main()
{
cout << endl << "Enter the golfer's filename: ";
getline(cin,filename);
cout << endl;
inScores.open(filename.c_str());
if(!inScores)
{
cout << "** " << filename << " does not exist. Please ";
cout << "check the spelling and rerun ";
cout << "the program with an existing golfer file. ** " << endl << endl;
return 1;
}
getline(inScores,name);
inScores >> loopCount;
cout << name << " has " << loopCount << " matches with scores of" << endl << endl;
inScores >> matchScore;
while (count <= loopCount)
{
cout << "Match " << count << ": " << matchScore << endl;
adder = adder + matchScore;
adder = adder + matchScore;
inScores >> matchScore;
count++;
}
cout << endl;
int(mean) = .5 + (adder / loopCount);
cout << "The mean score is " << mean << endl << endl;
inScores.close();
return 0;
}
As stated using loops will be necessary to get what you want. Also since the getline and extraction return false if they fail you can use them for the test in the loop:
ifstream inScores;
string filename;
string name;
int loopCount , matchScore;
int count = 1;
float mean = 0;
float adder = 0;
int main()
{
cout << endl << "Enter the golfer's filename: ";
getline( cin , filename );
cout << '\n';
inScores.open( filename );
if ( !inScores )
{
cout << "** " << filename << " does not exist. Please ";
cout << "check the spelling and rerun ";
cout << "the program with an existing golfer file. ** " << "\n\n";
return 1;
}
while ( getline( inScores , name ) )
{
if ( inScores >> loopCount )
{
cout << name << " has " << loopCount << " matches with scores of" << "\n\n";
}
else
{
cout << "File read error";
return 1;
}
for ( int count = 1; count <= loopCount; count++ )
{
if ( inScores >> matchScore )
{
cout << "Match " << count << ": " << matchScore << '\n';
adder = adder + matchScore;
}
else
{
cout << "File read error";
return 1;
}
}
}
cout << '\n';
int( mean ) = .5 + ( adder / loopCount );
cout << "The mean score is " << mean << "\n\n";
inScores.close();
return 0;
}

Cin loop never terminating

I'm having trouble getting my cin loop to terminate in my program. My program uses Linux redirection to read in input from the file hw07data, the data file look like this:
100 20 50 100 40 -1
A34F 90 15 50 99 32 -1
N12O 80 15 34 90 22 -1
The first portion is the total points for the class, the next lines are the students ID number followed by their scores, all terminated by -1.
My issue: my while loop never terminates when i run the command ./a.out < hw07data, could anyone look over my code and give me some hints? I dont want the answer, as this is homework, i just need some guidance. Thanks!!
#include <iostream>
#include <iomanip>
using namespace std;
const int SENTINEL = -1; //signal to end part of file
const int LTAB = 8; //left tab
const int RTAB = 13; //right tab
int main()
{
cout << "Grant Mercer Assignment 7 Section 1002\n\n";
cout << setprecision(2) << fixed << showpoint;
cout << left << setw(LTAB) << "ID CODE" <<
right << setw(RTAB) << "POINTS" <<
setw(RTAB) << "PCT" << setw(RTAB) <<
"GRADE" << endl;
double Percentage, //holds students percentage
AvgPercentage;
int Earnedpoints, //earned points for specific student
Totalpoints, //total points possible for all students
AvgPoints, //average points for all students
NumClass; //counts the number of students
Totalpoints = Earnedpoints = //set all vals equal to zero
AvgPoints = AvgPercentage = Percentage = NumClass = 0;
//first and last char for studentID
char Fchar,Lchar, Num1, Num2, Grade;
int TmpVal = 0; //temporary value
cin >> TmpVal;
while(TmpVal != -1) //reading in TOTAL POINTS
{
Totalpoints += TmpVal; //add scores onto each other
cin >> TmpVal; //read in next value
}
while(cin) //WHILE LOOP ISSUE HERE!
{
//read in student initials
cin >> Fchar >> Num1 >> Num2 >> Lchar >> TmpVal;
while(TmpVal != -1)
{
Earnedpoints += TmpVal; //read in points earned
cin >> TmpVal;
}
//calculate percentage
Percentage = ((double)Earnedpoints / Totalpoints) * 100;
AvgPercentage += Percentage;
NumClass++;
if(Percentage >= 90) //determine grade for student
Grade = 'A';
else if(Percentage >= 80 && Percentage < 90)
Grade = 'B';
else if(Percentage >= 70 && Percentage < 80)
Grade = 'C';
else if(Percentage >= 60 && Percentage < 70)
Grade = 'D';
else if(Percentage < 60)
Grade = 'F';
//display information on student
cout << left << Fchar << Num1 << Num2 << setw(LTAB) << Lchar << right << setw(RTAB-3) << Earnedpoints <<
setw(RTAB) << Percentage << setw(RTAB) << Grade << endl;
TmpVal = Earnedpoints = 0;
}
AvgPercentage /= NumClass;
cout << endl << left << setw(LTAB+20) << "Class size: " << right << setw(RTAB) << NumClass << endl;
cout << left << setw(LTAB+20) << "Total points possible: " << right << setw(RTAB) << Totalpoints << endl;
cout << left << setw(LTAB+20) << "Average point total: " << right << setw(RTAB) << AvgPoints << endl;
cout << left << setw(LTAB+20) << "Average percentage: " << right << setw(RTAB) << AvgPercentage << endl;
}
The output continues to ask for new input.
You may find answer there How to read until EOF from cin in C++
So you can read cin line by line using getline and parse the resulting lines, like that:
#include <iostream>
#include <sstream>
#include <string>
int main() {
int a, b;
std::string line;
while (std::getline(std::cin, line)) {
std::stringstream stream(line);
stream >> a >> b;
std::cout << "a: " << a << " - b: " << b << std::endl;
}
return 0;
}
EDIT: Do not forget to check parsing results and stream state for any failure!
You should always check that you input was successful:
if (std::cin >> TmpVal) {
// do simething with the read value
}
else {
// deal with failed input
}
In case of a failure you night want to check eof() inducating that the failure was due to having reached the end of the input.
To deal with errors, have a look at std::istream::clear() and std::istream::ignore().

C++ Output Errors

The output for this program, thanks to you guys, is fixed. Except for the studentNumber. I read the comment that I never set a value to it and that confused me.
void process_file(ifstream& input)
{
int thisStudent = 0;
StudentRecord student = StudentRecord();
while (thisStudent++ < CLASS_SIZE)
{
student.input(input, thisStudent);
student.computeGrade();
student.output();
}
}
would this not set studentNumber equal to 0 then add +1 every time it runs through the loop.
// Author:
// Assignment 8
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
ofstream outputfile("output.txt");
const int MAX_FILE_NAME = 35;
const int CLASS_SIZE = 5;
class StudentRecord
{
public:
void input( ifstream& input,int studentid);
void computeGrade();
void output();
private:
int studentNumber;
double exam1;
double exam2;
double exam3;
double exam4;
double average;
char grade;
};
void open_input(ifstream& input, char name[]);
void process_file(ifstream& input);
int main()
{ char again;
char file_name[MAX_FILE_NAME + 1];
ifstream input_numbers;
cout << "This program can calculate the exam average and grade for\n"
<< "each student.\n" << endl;
system("pause");
do
{
system("cls");
open_input(input_numbers, file_name);
process_file(input_numbers);
input_numbers.close();
cout << "\nDo you want to process another file (Y/N)? ";
cin >> again;
cin.ignore(256, '\n');
} while ( again == 'y' || again == 'Y');
cout << "\nEnd of Program!" << endl;
outputfile << "\n\nThanks for using GradeCalc!\f";
outputfile.close();
return 0;
}
void process_file(ifstream& input)
{
int thisStudent = 0;
StudentRecord student = StudentRecord();
while (thisStudent++ < CLASS_SIZE)
{
student.input(input, thisStudent);
student.computeGrade();
student.output();
}
}
void open_input(ifstream& input, char name[])
{ int count = 0;
do
{ count++;
if (count != 1)
{ cout << "\n\aInvalid file name or file does not exist. Please try again."
<< endl;
}
cout << "\nEnter the input file name (maximum of " << MAX_FILE_NAME
<< " characters please)\n:> ";
cin.get(name, MAX_FILE_NAME + 1);
cin.ignore(256, '\n');
input.clear();
input.open(name,ios_base::in);
} while (input.fail() );
}
void StudentRecord::input(ifstream& input, int studentid)
{
input >> exam1 >> exam2 >> exam3 >> exam4;
}
void StudentRecord::computeGrade()
{
average = (exam1 + exam2 + exam3 + exam4) / 4 ;
if (average >= 90)
grade = 'A';
else if (average >= 80)
grade = 'B';
else if (average >= 70)
grade = 'C';
else if (average >= 60)
grade = 'D';
else if (average < 60)
grade = 'F';
}
void StudentRecord::output()
{
cout << "\n\nThe record for student number:" << setw(8) << studentNumber << endl;
cout << "The exam grades are:" << setw(8) << exam1 << exam2 << exam3 << exam4 << endl;
cout << "The numeric average is:" << setw(8) << average << endl;
cout << "and the letter grade assigned is:" << setw(8) << grade << endl;
}
Well, studentNumber is garbage because you never put a value in it. So it just has whatever happened to already be in memory at that location.
The exam grades print out wrong because commas in C++ don't do what you think they do, and that's also why adding an endl; to it gives you an error.
The formatting I'm going to let you work out for yourself. You should consider reading up on output or at least doing some trial and error.
One of the errors is that instead of this:
cout << "The exam grades are:" << setw(8) << exam1, exam2, exam3, exam4;
I think you mean this:
cout << "The exam grades are:" << setw(8) << exam1 << exam2 << exam3 << exam4 << endl;
CLASS_SIZE is defined as 5, so this loop:
while (thisStudent++ < CLASS_SIZE)
will iterate 6 times.
Also
cout << "The exam grades are:" << setw(8) << exam1, exam2, exam3, exam4;
This outputs exam1, and then evaluates and does nothing with the rest of the variables.
70 80 90 95 95 85 90 80 75 85 70 80 55 85 50 70 45 50 40 35
does it have the spaces? If yes, you need to ignore them. input >> exam1 >> exam2 >> exam3 >> exam4; would load space into one of the exam variables.
-- edit for MooingDuck --
#include <iostream>
#include <sstream>
using namespace std;
int main() {
cout << "main() ENTRY" << endl;
stringstream s1(ios_base::in | ios_base::out),
s2(ios_base::in | ios_base::out);
int i = -1;
s1 << "111 222";
s1 >> i; cout << i << endl;
s1 >> i; cout << i << endl;
s2 << "111 222";
s2 >> noskipws;
s2 >> i; cout << i << endl;
s2 >> i; cout << i << endl;
return 0;
}
Output:
main() ENTRY
111
222
111
0