Thread: help me understand this

  1. #1
    Weak. dra's Avatar
    Join Date
    Apr 2005
    Posts
    166

    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.

    [Edit] 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.
    Last edited by dra; 06-01-2005 at 01:30 AM.

  2. #2
    Registered User
    Join Date
    May 2005
    Posts
    73
    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...
    Last edited by Deo; 06-01-2005 at 02:22 AM.

  3. #3
    Weak. dra's Avatar
    Join Date
    Apr 2005
    Posts
    166
    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. #4
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    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.
    Last edited by hk_mp5kpdw; 06-01-2005 at 05:46 AM.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  5. #5
    Weak. dra's Avatar
    Join Date
    Apr 2005
    Posts
    166
    Quote 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. #6
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    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.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  7. #7
    Weak. dra's Avatar
    Join Date
    Apr 2005
    Posts
    166
    thanks for the tip.

Popular pages Recent additions subscribe to a feed