# Thread: help me understand this

1. ## help me understand this please

Code:
```#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

using std::max;

using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::istream;
using std::ostream;
using std::setprecision;
using std::setw;
using std::sort;
using std::streamsize;
using std::string;
using std::vector;

struct Student_info {
string name;
double midterm, final;
vector<double> homework;
};	// note the semicolon--it's required

// compute the median of a `vector<double>'
// note that calling this function copies the entire argument `vector'
double median(vector<double> vec)
{
typedef vector<double>::size_type vec_sz;

vec_sz size = vec.size();
if (size == 0)
throw domain_error("median of an empty vector");

sort(vec.begin(), vec.end());

vec_sz mid = size/2;

return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid];
}

// compute a student's overall grade from midterm and final exam grades and homework grade
double grade(double midterm, double final, double homework)
{
return 0.2 * midterm + 0.4 * final + 0.4 * homework;
}

// compute a student's overall grade from midterm and final exam grades
// and vector of homework grades.
// this function does not copy its argument, because `median' does so for us.
double grade(double midterm, double final, const vector<double>& hw)
{
if (hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));
}

double grade(const Student_info& s)
{
return grade(s.midterm, s.final, s.homework);
}

// read homework grades from an input stream into a `vector<double>'
istream& read_hw(istream& in, vector<double>& hw)
{
if (in) {
// get rid of previous contents
hw.clear();

// read homework grades
double x;
while (in >> x)
hw.push_back(x);

// clear the stream so that input will work for the next student
in.clear();
}
return in;
}

istream& read(istream& is, Student_info& s)
{
// read and store the student's name and midterm and final exam grades
is >> s.name >> s.midterm >> s.final;

read_hw(is, s.homework);  // read and store all the student's homework grades
return is;
}

bool compare(const Student_info& x, const Student_info& y)
{
return x.name < y.name;
}

int main()
{
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;

// read and store all the records, and find the length of the longest name
while (read(cin, record)) {
maxlen = max(maxlen, record.name.size());
students.push_back(record);
}

// alphabetize the records
sort(students.begin(), students.end(), compare);

for (vector<Student_info>::size_type i = 0;
i != students.size(); ++i) {

// write the name, padded on the right to `maxlen' `+' `1' characters
cout << students[i].name
<< string(maxlen + 1 - students[i].name.size(), ' ');

// compute and write the grade
try {
double final_grade = grade(students[i]);
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec);
} catch (domain_error e) {
cout << e.what();
}

cout << endl;
}

return 0;
}```
Can someone help me understand this example code from Accelerated C++?

I don't quite understand how it works.

I understand that the while(read(cin, records)) branches off to the read() function and allows you to enter the name, midterm, final grades, then branches off into read_hw() to input the homework grades.

What I don't understand is how this can work:

person1 (name)
100 (midterm)
100 (finals)
(then a few more numbers for homework)
person2 (name)
......(same thing over again).

I don't understand how the program knows to put the second name into s.name

Thanks in advance.

 I think i kind of understand but i don't know. read_hw() reads the homework grades and that's it. if it encounters anything besides something that constitutes as a double, it ignores it, clears the input stream of the error caused by the input of name, returns from read_hw(), read() then returns and ends, and because of the while function, the read() function is again called and the name we previously entered counts as the first thing read into is, which happens to be s.name?

Am I at least close? lol.

2. Code:
```struct Student_info
{
string name;
double midterm, final;
vector<double> homework;
};```
You know what a vector is right? Basically just an array with no limit. It expands when entries are added and decreases when entries are removed.

Code:
```vector<Student_info> students;
Student_info record;```
students will represent a list of students and their info based on the above structure.

record is a single Student_info structure. This is what temporarily holds the input gathered from read().

Code:
```while (read(cin, record))
{
maxlen = max(maxlen, record.name.size());
students.push_back(record);
}```
So pass in our temporary record structure into read() where it will be represented by the variable s. Notice it is being passed as a reference meaning we will be altering the record structure directly.

Code:
```is >> s.name >> s.midterm >> s.final;
read_hw(is, s.homework);

equates to

cin >> record.name >> record.midterm >> record.final;
read_hw(cin, record.homework);```
Store the students name, midterm, and final into record structure then call readhw() to get homework grades. Notice we are passing s (record structure) into readhw() by reference thus any changes made will be directly to record.homework structure.

Code:
```hw.push_back(x);

equates to

record.homework.push_back(x)```
While there is more homeworks being inputed add to record.homework. push_back() is a function of the <vector> class that basically says add another entry.

Code:
`in.clear();`
Clear stream so that when input is to be retrieved from next student there will be no data left from previous student. Then return to main()

Code:
`students.push_back(record);`
Add our newly filled record structure that contains the input we just got to our student structure.

This process is repeated until there are no more students.

1. Record structure is filled up.
2. Record structure is added to student structure.
3. Record structure filled again.
4. Record structure added to student structure.
etc...

3. yes i understand those concepts.

what i don't understand is that when you're in read_hw() you're reading homework grades, and it's looking for input types of double. i'm confused about the fact that when you are in read_hw() and its waiting for you in enter numbers and instead you enter the name of the next student, it pushes record back into vector<student_info> students, and then the name you entered is read into s.name.

does read_hw() just ignore it, returns control to read(), read() returns also, record is pushed to the back of students, and read() is called again and the second name is read into s.name?

4. Code:
```istream& read_hw(istream& in, vector<double>& hw)
{
if (in) {
// get rid of previous contents
hw.clear();

// read homework grades
double x;
while (in >> x)
hw.push_back(x);

// clear the stream so that input will work for the next student
in.clear();
}
return in;
}

istream& read(istream& is, Student_info& s)
{
// read and store the student's name and midterm and final exam grades
is >> s.name >> s.midterm >> s.final;

read_hw(is, s.homework);  // read and store all the student's homework grades
return is;
}

...

int main()
{
...

// read and store all the records, and find the length of the longest name
while (read(cin, record)) {
maxlen = max(maxlen, record.name.size());
students.push_back(record);
}

...```
As long as a value is read in by the in stream that can be successfully converted to a type double then the loop continues pushing homework values onto the homework vector. Once a value that cannot be converted to a type double is encountered, i.e. a person's name which is a string, the stream goes into an error state and we drop out of the while loop in the read_hw function. The error flag is then cleared and we return control to the read function which then returns to the while (read(cin, record)) loop back in main. There we then push the current student's record we just processed onto the students vector and go back to calling the read function in the next iteration of the while loop to process the next students information. This starts by getting the name that is still in the stream that initially caused the stream to go into an error state. At that time we had tried to process a double but can now process it successfully since we are now getting a string type off of the stream.

5. Originally Posted by hk_mp5kpdw
As long as a value is read in by the in stream that can be successfully converted to a type double then the loop continues pushing homework values onto the homework vector. Once a value that cannot be converted to a type double is encountered, i.e. a person's name which is a string, the stream goes into an error state and we drop out of the while loop in the read_hw function. The error flag is then cleared and we return control to the read function which then returns to the while (read(cin, record)) loop back in main. There we then push the current student's record we just processed onto the students vector and go back to calling the read function in the next iteration of the while loop to process the next students information. This starts by getting the name that is still in the stream that initially caused the stream to go into an error state. At that time we had tried to process a double but can now process it successfully since we are now getting a string type off of the stream.
Okay right on. Sounds almost like what i said earlier. Thanks.

6. Whenever you have a situation like this where you cant see whats happening from just looking at your code run it in a debugger and singlestep through it. This will familiarise you with the path of execution and highlight each line of code as its processed.

7. thanks for the tip.

Popular pages Recent additions