Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 4 Organizing Programs and Data. Objectives Understand the use of functions in dividing a program into smaller tasks. Discover how parameters can.

Similar presentations


Presentation on theme: "Chapter 4 Organizing Programs and Data. Objectives Understand the use of functions in dividing a program into smaller tasks. Discover how parameters can."— Presentation transcript:

1 Chapter 4 Organizing Programs and Data

2 Objectives Understand the use of functions in dividing a program into smaller tasks. Discover how parameters can be passed to functions both by value and by reference. Introduce throwing and handling exceptions. Explore the definition and use of records. Learn how to divide a program into individual files, including the use of header files. Explore basic preprocessor commands. Use Random class objects to create random numbers.

3 C++ Whenever the C++ language designers had two competing ideas as to how they should solve some problem, they said, “OK, we’ll do them both”. So the language is too baroque for my taste. – Donald E Knuth C++: an octopus made by nailing extra legs onto a dog. – Steve Taylor

4 Functions We need to break large problems into smaller more manageable tasks. – Modularization and encapsulation – Code reuse The following function computes the grade. double grade(double midterm, double final, double homework) { return 0.2 * midterm + 0.4 * final + 0.4 * homework; }

5 Functions In C++ functions must specify their return type. They must also specify the types of all of their parameters. When we call the function we must supply a corresponding list of arguments (actual parameters) that have the same types. To call our function we could do something like the following. cout << grade(midterm, final, homework); A function can only be called after it is declared.

6 Parameters Parameters can be expressions as well as variables. cout << grade(midterm, final, sum / count); This is a call by value. – The function operates on copies of the actual parameters. – If their values are modified it will not change the actual parameters.

7 Finding Medians double median(vector vec) { typedef vector ::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]; } Note the vector is now called vec because this is a general purpose function that could calculated the median of any vector. The actual parameter that corresponds to vec will not be sorted since the function operates on a copy.

8 Throwing an Exception The median function throws an exception if the vector is empty. if (size == 0) throw domain_error("median of an empty vector"); If this happens, execution of the function will stop. Control will return to the location where the function call was made along with an exception object. domain_error is defined in and is used to report that a function’s argument is not acceptable.

9 Call by Reference double grade(double midterm, double final, const vector & hw) { if (hw.size() == 0) throw domain_error("student has done no homework"); return grade(midterm, final, median(hw)); } The & in the last parameter is very important. This indicates a call by reference. The function will operate on the formal parameter.

10 A Reference to a Variable We can create a reference to any object. vector homework; vector & hw = homework; We now have two variable names that refer to the same object in memory. If we do anything to hw it is the same as doing it to homework (and vice versa).

11 Constant Reference Why pass the vector by reference? – The computer does not need to make a copy of the original. – The program will run faster and use less memory. – This is only an issue if the vector is large. We still do not intend to make any changes to the original. – We add the const keyword so that we cannot accidentally modify the vector. Passing a constant reference (instead of passing by value) is sometimes useful to improve performance.

12 Overloading Function Names Notice there are two functions named grade. double grade(double midterm, double final, double homework) double grade(double midterm, double final, const vector & hw) One even calls the other. This is confusing for people but not for C++. Not only the name, but the number and type of parameters are used to identify a function. Having more than one function with the same name is call function overloading.

13 Reading in Data Suppose we want to read in data. We want a function that does two things. – Check to see if the read attempt is successful. – Return the value read (if successful). We can only have one return value. Solution: pass a parameter by reference and modify it.

14 Reading in Data The following code will do what we want. istream& read_hw(istream& in, vector & hw) { // read stuff return in; } This accepts references to an input stream and a vector of doubles. – Both will be modified. – Both must be lvalues, something that has a name and can be modified (not an expression or a const ).

15 Checking the Stream Since the return value is a reference to the input stream, the following code makes sense. if (read_hw(cin, homework)) { //if stuff } This is the same as read_hw(cin, homework); if (cin) {\if stuff} In either case the “if stuff” will only be done if cin is available for reading.

16 Preparing to Read from a File A file does not follow instructions – our program must adapt to what is in the file. We need to read in the following: – Name – Midterm exam grade – Final exam grade – A list of homework grades Since the length of the homework list is variable, how can we tell when it is done? We can try to read a double, this read will fail if we try to read someone’s name.

17 Reading Homework Scores We will create a function to read the homework scores into a vector. Issues to consider: – The vector needs to be empty. Use the clear method to empty the vector. We probably do not need to do this but better safe than sorry. – We will read until we encounter data that cannot be read as double. This will create a failure state on the output stream. We should clear this so the next read won’t have problems. Again there is a clear method to take care of this.

18 Reading Homework Scores istream& read_hw(istream& in, vector & hw) { if (in) { hw.clear(); // get rid of previous contents // read homework grades double x; while (in >> x) hw.push_back(x); in.clear(); // clear the stream so future input will work } return in; }

19 Passing Parameters There are three options when passing parameters. Pass by value. – Original argument is protected from changes. – Copy can be modified without changing original. Pass by reference. – Parameter and original are different names for the same object. – Changes will modify the original. – Arguments must be lvalues. Passing a constant reference. – Parameter and original are different names for the same object but the parameter cannot be modified. – Original argument is protected from changes. – Better performance than pass by value.

20 Modified Grading Program int main() { // ask for and read the student's name cout << "Please enter your first name: "; string name; cin >> name; cout << "Hello, " << name << "!" << endl; // ask for and read the midterm and final grades cout << "Please enter your midterm and final exam grades: "; double midterm, final; cin >> midterm >> final; // ask for the homework grades cout << "Enter all your homework grades, " "followed by end-of-file: ”;

21 Modified Grading Program vector homework; // read the homework grades read_hw(cin, homework); // compute and generate the final grade, if possible try { double final_grade = grade(midterm, final, homework); streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error) { cout << endl << "You must enter your grades. " "Please try again." << endl; return 1; } system("pause"); return 0; }

22 Catching Exceptions The new grading program is similar to the original except that it has offloaded much of it operation to functions. The new part here is catching the exceptions that might be thrown in grade and median. The procedure is similar to Python. try{ // stuff that might throw an exception } catch (error_type) { // stuff to do when this type of error occurs }

23 Catching Exceptions Remember that if an exception is thrown in a try, execution immediately passes to the catch. This can lead to odd behavior if you are not careful. Try to avoid having more than one side effect per statement inside a try.

24 More on Catching Exceptions Exception classes include: logic_error, domain_error, invalid_argument, length_error, out_of_range, runtime_error, range_error, overflow_error, underflow_error When we catch an exception e we can use the method e.what() to find out what happened to cause the error.

25 Records Suppose we want to read in the data for several students from a file. We need a way to group the data for each student and store it using a single variable name. C++ allows us to create a struct that contains data members. – Similar to a class but without methods. struct Student_info { string name; double midterm, final; vector homework; }; // note the semicolon is required

26 Reading into Records The following function reads the data for a Student_info record. istream& read(istream& is, Student_info& s) { is >> s.name >> s.midterm >> s.final; read_hw(is, s.homework); return is; } This function has the input stream and Student_info record as parameters. It uses the previous read_hw function to read the homework grades.

27 Computing Grades We also need to be able to compute a grade from each Student_info record. double grade(const Student_info& s) { return grade(s.midterm, s.final, s.homework); } Notice this is a wrapper for the previous grade function. The two grade functions are distinguished by their parameters. The earlier grade function handles all exceptions.

28 Vector of Records To store all of our records we might want to put them into a vector. That way we won’t need to find an individual name for each record. We can sort the records. – Alphabetically – Grade – Name length – etc. To sort a list of records we need to define what we mean by sorting by providing the vector sort method with a predicate.

29 Sorting Predicate The predicate for sorting is a Boolean function that accepts two items in the list and returns true if the first parameter should come earlier in the sorted vector. bool compare(const Student_info& x, const Student_info& y) { return x.name < y.name; } When comparing strings < applies normal dictionary ordering To sort the vector students we do the following. sort(students.begin(), students.end(), compare);

30 main() int main() { vector students; Student_info record; string::size_type maxlen = 0; // the length of the longest name // read and store all the students' data. // Invariant:`students' contains all the student records read so far //`maxlen' contains the length of the longest name in `students' while (read(cin, record)) { // find length of longest name maxlen = max(maxlen, record.name.size()); students.push_back(record); } // alphabetize the student records sort(students.begin(), students.end(), compare);

31 main() // write the names and grades for (vector ::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; } system(“pause”); return 0; }

32 Max The function max is define in. It compares two items of the same type and returns the larger. This is why maxlen is of type string::size_type.

33 Nameless string The output produces a nameless string string(maxlen + 1 – student[i].name.size(), ‘ ‘) This string has the specified number of characters but they are all blank. This string is never given a name – effectively making it an expression. It is used to pad the output to make for attractive formatting.

34 Multiple Files The program is getting large to put in a single file. We can break our code into multiple files and include them in a similar manner to the standard template headers. #include “median.h” C++ supports separate compilation. – Each file is compiled separately so a change in one file does not mean the entire program must be recompiled.

35 Vs “…” #include means include a system header. #include “…” means include a user-defined header.

36 Header Files If we wanted to include the entire median function in the header file it would work, but it would not allow for separate compilation. To do this we create a file median.cc (.cp or.cpp or.C) that contains the median function. We also create a header file median.h file that contains the interface for the median function.

37 Header Files The median header would look like the following. // median.h #include double median(std::vector ) This is a function declaration for median. This is the promise to create a function with the specified interface. Either the function definition itself or a declaration must precede the use of a function in a program. Note, the function declaration doesn’t make sense without.

38 median.cc #include // to get the declaration of `sort' #include // to get the declaration of `domain_error' #include // to get the declaration of `vector’ using std::domain_error; using std::sort; using std::vector; #include "median.h” double median(vector vec) { typedef vector ::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]; }

39 Minimal Header Files Keep header files as simple as possible. – We did not put using std::vector in the header and used std::vector in the function declaration. – Code using the header may not want to be locked into using the standard vector package in the rest of the program. – Use as few names, libraries, other includes, etc. as possible in header files.

40 Random One example of a user-defined file we might want to include is random.h. #include”random.h” Allows us to create objects of class Random. When you create one of these objects you can choose whether or not to seed the random number generator so you get different numbers each time.

41 Random Create a Random object where the same sequence of numbers will be produced each time. Random rand; Create a Random object where the sequence will be different each time. Random rand(false);

42 Random This class has the following helpful methods. rand.Random_real() – produces a random double between 0 and 1. rand.Random_integer(low, high) – produces a random integer between low and high inclusive (in the range [ low, high ]).

43 Protecting Header Files What if an header (or even different versions of the header) gets included more than once? This could lead to very odd behavior. We can modify the header to prevent this. #ifndef GUARD_median_h #define GUARD_median_h #include double median(std::vector ); #endif

44 #ifndef The #ifndef directive checks if the preprocessor variable GUARD_median_h is defined. If the variable is not yet defined all the code between it and the #endif directive is executed. If the variable is defined then the code is skipped. The directive #define creates the variable the first time this header file is encountered.

45 C++ Compilation Process Preprocess – the C++ preprocessor makes a pass through the code and only pays attention to commands beginning with #. – copies in the contents of the included header files – generates macro code – replaces symbolic constants with their values. Compile – the expanded source code file is compiled into the assembly language for the platform. (.a file) Assemble – the assembler code is assembled into the object code for the platform. (.o file) Link – the object code files are linked together to produce an executable file. (.exe file)

46 C++ Compilation Process An integrated development environment (IDE) generally performs all 4 steps at one time. The first three steps only need to be performed on code that has changed. Large programs could take a long time to compile completely (hours to days) We can interrupt the process. –.o files generated using different languages can be linked. – A developer could provide a library as a.o file without providing the source code.

47 Projects in DevC++ In order to have multiple files in a program in DevC++ we need to create a project. From the File menu select New and then Project. This will pop up a dialogue box asking your to name your project and what type of project it will be.

48 Projects in DevC++ Select Console Application, give your project a name and make sure it is a C++ Project before clicking OK.

49 Projects in DevC++ Next, you will need to select a location to save your project. Your m: drive would be a good location. It is also a good idea to create a folder to store your new project.

50 Projects in DevC++ When you create a project a main file is created for you. You can either edit this default or delete it and add your own. You should copy all the code files and their associated header files to your project folder. At this point the files are visible to the compiler but are not yet officially part of your project. Code files (.cc,.cp,.C,.cpp ) need to be added to the project. Header files (.h ) do not need to be added.

51 Projects in DevC++ Finally, you add files to the project by going to the Project menu and selecting Add to Project. Deleting files is also done by going to the Project menu and selecting Remove from Project.

52 Projects in DevC++ The files that are part of your project are in a list on the left hand side of the DevC++ screen.

53 Projects in DevC++ Click on these files to edit them. Compile and run your code as usual.

54 Partitioning We often want related code together in the same C++ file. –Student_info structure and the related functions should be together. –grade in all its overloaded forms should be together. –median is in a file by itself.

55 Student_info.h #ifndef GUARD_Student_info #define GUARD_Student_info #include struct Student_info { std::string name; double midterm, final; std::vector homework; }; bool compare(const Student_info&, const Student_info&); std::istream& read(std::istream&, Student_info&); std::istream& read_hw(std::istream&, std::vector &); #endif

56 Student_info.h We need and because they define types used in the function declarations. Similarly we need to define the struct Student_info here because it is used in the function declarations.

57 Student_info.cc #include "Student_info.h" using std::istream; using std::vector; bool compare(const Student_info& x, const Student_info& y) { return x.name < y.name; } istream& read(istream& is, Student_info& s) {... } istream& read_hw(istream& in, vector & hw) {... }

58 Student_info.cc Notice we are including the declarations for these functions and the definition of the struct Student_info by including the header file. There is no reason to avoid the using command because this code will not be inserted into other files using #include.

59 grade.h #ifndef GUARD_grade_h #define GUARD_grade_h #include #include "Student_info.h" double grade(double, double, double); double grade(double, double, const std::vector &); double grade(const Student_info&); #endif

60 grade.cc #include #include "grade.h" #include "median.h" #include "Student_info.h" using std::domain_error; using std::vector; double grade(double midterm, double final, double homework) { return 0.2 * midterm + 0.4 * final + 0.4 * homework; } double grade(double midterm, double final, const vector & 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); }

61 grade.cc Note, we do not really need to include Student_info.h because it is included in grade.h (which is also included here). Because we used the guard variable in Student_info.h, this is not a problem.

62 Main Program #include #include "grade.h" #include "Student_info.h" using std::cin; using std::setprecision; using std::cout; using std::sort; using std::domain_error; using std::streamsize; using std::endl; using std::string; using std::max; using std::vector;

63 Main Program int main() { vector students; Student_info record; string::size_type maxlen = 0; while (read(cin, record)) { maxlen = max(maxlen, record.name.size()); students.push_back(record); } sort(students.begin(), students.end(), compare);

64 Main Program for (vector ::size_type i = 0; i != students.size(); ++i) { cout << students[i].name << string(maxlen + 1 - students[i].name.size(), ' '); 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; } system("pause"); return 0; }

65 Formatting Output In order to create columns in our output it is nice to be able to determine the number of spaces to use. There are two ways to do this. –outputStream.width(n) – this sets the width to n spaces for the next output, padded to the left. The return value is the previous width. –outputStream << setw(n) – this does the same thing.

66 Homework Chapter 4 (page 73) Total 25 pts possible. – 4-0 – Create a function called swap that accepts two integer parameters as references and exchanges their values. (email, 10 pts) – Create a function to calculate the result of the quadratic formula. Throw an exception if the discriminate is negative. Write a main function that calls the function, catches any exceptions, and prints an appropriate message in all cases. (email, 15 pts)

67 Homework Chapter 4 (page 73) – The program phone.cc needs to be divided into several files for individual compilation. Divide this program into at least 3.cc files that contain related functions. Create appropriate header files for each.cc file. Be sure to minimize the number of names used in each header. (email, 15 pts) – 4-8 (paper, 5 pts)

68 Project 1 (part 1) Create a program generates random entries suitable for reading into Student_info records. One way to do this is to read the words.txt file into a vector of strings. Use the Random package to randomly select entries from the vector as names. Then randomly choose grades in the range 0-100 (at least 3) to follow each name. Have your program output 10,000 records to a file. You may want to bias your scores so that most (but not all) of your students pass. (email, 15 pts)


Download ppt "Chapter 4 Organizing Programs and Data. Objectives Understand the use of functions in dividing a program into smaller tasks. Discover how parameters can."

Similar presentations


Ads by Google