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().
Related
So I am working on this program, and i have it mostly complete. I am just having trouble with running the loop again. If i run the loop again, it messes up by displaying both of the questions in the function at the same time.
And after the program is finished, i need to display all of the iterations at the same time.
// This program will gather the information for the quizzes that have been taken in a course to date
and // output the information into a report on the screen.
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
// Function Prototypes
void getQuiz(string&, int&, int&);
int main()
{
char grade;
char ans = 'Y';
string name;
int quiz_number = 0;
int score;
int poss_score;
int counter = 1;
double percentage;
// Explain what the program will do
cout << "This program will ask the user to enter the name of a quiz, the score aquired, and the
total possible score.\n";
cout << "It will display a report that will show the quiz number, the name, the points, total,
percentage, and the letter grade." << endl << endl;
do {
// Display count
cout << counter;
cout << endl << endl;
// Call function
getQuiz(name, score, poss_score);
// Accumulate the number of times the loop is run
counter++;
cout << "Would you like to add another quiz? (Y) or (N)" << endl;
cin >> ans;
} while (ans == 'y' || ans == 'Y');
cout << endl << endl;
// Calculate the percentage
percentage = score * 100 / poss_score;
// Get the letter grade
if (percentage <= 100 && percentage >= 90)
grade = 'A';
else if (percentage <= 89 && percentage >= 80)
grade = 'B';
else if (percentage <= 79 && percentage >= 70)
grade = 'C';
else if (percentage <= 69 && percentage >= 60)
grade = 'D';
else if (percentage <= 59)
grade = 'F';
// Display the results in a table
cout << setw(5) << " Quiz" << setw(20) << " Title" << setw(20) << " Points" << setw(10) << "
Total" << setw(10) << " Percent" << setw(10) << " Grade" << endl << endl;
cout << setw(5) << counter << setw(20) << name << setw(20) << score << setw(10) << poss_score <<
setw(10) << percentage << setw(10) << grade << endl;
return 0;
}
void getQuiz(string& name, int& score, int& poss_score)
{
// Get the name of the quiz
cout << "\nWhat is the name of the quiz? " << endl;
getline(cin, name);
cout << "\nWhat was the score aquired? " << endl;
cin >> score;
cout << "\nWhat was the total possible score acheivable? " << endl;
cin >> poss_score;
}
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.
I am not sure how to stop my sentinel value from being read into my array which is causing an error with my total and average calculation. Can anyone help?
Here is the while loop:
while (grade != -1)
{
cin >> grade;
gradesArray[count] = grade;
total += gradesArray[count];
average = total / count;
count++;
}
cout << "You have entered " << count << " grades." << endl;
cout << "The average of these grades is " << average << endl;
while (std::cin >> grade && grade != -1)
Here is my modified code, but the average outputs an average that is too high.
#include<iostream>
using namespace std;
int main()
{
int count = 0, grade = 0;
double total = 0, average;
const int numGrades = 20;
int gradesArray[numGrades];
cout << "Welcome to the grade calulator!" << endl;
cout << "Enter up to twenty grades, when done enter -1: " << endl;
while (cin >> grade && grade != -1)
{
gradesArray[count] = grade;
total += gradesArray[count];
average = total / count;
++count;
}
cout << "You have entered " << count << " grades." << endl;
cout << "The average of these grades is " << average << endl;
system("pause");
return 0;
}
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.
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