Recall how we did yards, feet, and inches in lecture:
// get whole measurement in inches yards = inches / inches_p_yrd; // retrieve whole yards inches = inches % inches_p_yrd; // remove whole yards to get // leftover inches feet = inches / inches_p_ft; // retrieve whole feet inches = inches % inches_p_ft; // remove whole feet to get // leftover inches
See how pairs of /% operations are used to retrieve a whole number of parts and then get what's left of the smaller unit. Or, pictorially:
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
49 inches. Counting out the whole yards:
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIII Y IIIIIIIIIIIII
Leaves 13 inches. The only trick in C++ is that it takes two operations to do this retrieve and leftover: / and then %. Again, we have 13 inches, taking out the whole feet:
IIIIIIIIIIII I F I
Leaves 1 inch. Mathematically what we did was:
__1_R13 49 = 36*1 + 13 36 / 49 36 ---- 13 __1_R1 13 = 12*1 + 1 12 / 13 12 ---- 1
But, in C++, we are a little more compact:
1 = 49 / 36 13 = 49 % 36 1 = 13 / 12 1 = 13 % 12
This pattern can be followed for any set of unit conversions: metric, English, monetary, etc. And it extends to any number of units:
// get whole measurement in inches miles = inches / inches_p_mi; // retrieve whole miles inches = inches % inches_p_mi; // remove whole miles to get // leftover inches yards = inches / inches_p_yrd; // retrieve whole yards inches = inches % inches_p_yrd; // remove whole yards to get // leftover inches feet = inches / inches_p_ft; // retrieve whole feet inches = inches % inches_p_ft; // remove whole feet to get // leftover inches
Even better, you can even skip parts:
// get whole measurement in inches inches = inches % inches_p_yrd; // remove whole miles, yards, etc. // to get leftover inches feet = inches / inches_p_ft; // retrieve whole feet inches = inches % inches_p_ft; // remove whole feet to get // leftover inches
(This only works when the constants being divided by are multiples of each other -- related, if you will.)
There are two forms of typecasting: C-style and (new) C++-style. C-style places the datatype you are casting to and places it in parentheses before the item (variable/expression) to be cast:
yard_frac = (double)inches/inches_p_yrd; or grow_rate = (double)new_popul/old_popul;
The (new) C++-style typecast uses the static_cast
keyword:
yard_frac = static_cast<double>(inches)/inches_p_yrd; or grow_rate = static_cast<double>(new_popul)/old_popul;
Both work when casting to any datatype, one is just shorter.
Warning: It can be easy to slip with the parentheses:
yard_frac = static_cast<double>(inches/inches_p_yrd); or grow_rate = static_cast<double>(new_popul/old_popul);
Here we are performing an integer division and then casting that integer result to a double. We've still lost the decimal places we were after!
But you can screw up with the C-style (it's just more difficult), too:
average = (double)(min + max)/2;
Might be mis-typed as:
average = (double)min + max/2;
But that isn't really the typecast's fault -- it was an algebra error!
When designing a function, try to make it as re-usable as you can. Note how the read function simply reads the input of the inches. It doesn't prompt. That way the programmer of the main (still you here, but possibly someone else later) can simply decide how to prompt before calling the read function.
This main-programmer decided to prompt for all the bars' lengths at once:
cout << "Enter lengths of three bars: "; bar1 = read(); bar2 = read(); bar3 = read();
They could just as easily have decided to prompt for them individually:
cout << "Enter length of first bar: "; bar1 = read(); cout << "Enter length of second bar: "; bar2 = read(); cout << "Enter length of third bar: "; bar3 = read();
Since the read function is so general, it is easy to use it in many different ways.
Likewise, the conversion functions are re-usable since they only deal with the units -- not the item being measured. If the caller is converting distances between cities on a map, fine. If they are converting lenths of bars, cool. If they are converting meters to miles -- try another library. *smile*
Other functions aren't there to be re-used many times. They are there to clean up this application. The other functions in this program are of this type. The display function encapsulates our output format. If we wanted to print other things in this same format, we could re-use it -- although that seems less than likely (*grin*). But at the very least, it is tucked out-of-the-way in a separate function.
The greeting and goodbye functions likewise remove cluttering output statements from the main program.
In algebra, you would evaluate a function at a particular value of the independent variable. Programmers are more succinct. We call (or invoke) a function. The call is responsible for giving the function any values it requires. Note how the greeting and goodbye functions take no arguments (have a void or empty argument list) and so the call has simply empty parenthesis at the end:
greeting(); goodbye();
These functions also return no value and so they are simply in the statement alone (terminated by the ; as usual).
The print function, though, takes a single argument which is the area to display. But since it doesn't return anything either, it is also alone on the statement:
display(inches, yards, feet, inches_left, yard_frac);
The conversion functions requires an input value and returns the single calculated value:
inches_left = in_rem_ft(inches_left);
Finally the read function needs nothing to start working, but returns the value that was input:
inches = read();
So if the function needs nothing to start working, it will have empty parenthesis after its name in the call. If a function returns a calculated value, it should be stored with an assignment statement. If it returns nothing, the call must be the entire statement.
Arguments are programmers way of saying 'independent variable'. They are the required inputs to the function which let it do its job. If none are needed (if a function simply reads from the user directly), the word void can be placed inside the function's head -- but NOT in the call!
An argument (or input) is a value that has already been stored or calculated in the program, but that this function needs in order to perform its calculations (or whatever job). If the user has already entered a value and a function called later needs that value, we send it (or pass it) to the function through the argument list.
There are many types of arguments. Formal arguments are those listed in the function's head (be it on the definition or the prototype). These arguments have a data type and a name. The name of a formal argument is only valid during the funciton's execution. After the return statement executes, all formal arguments disappear (just like local variables do).
Actual arguments are those in the function call. An actual argument is just a value: literal, constant, calculation, varible. No types are mentioned because they are implicit in the calculation or the variable/constant declaration.
Finally, the arguments we've seen up till now are called value arguments because only the value of the actual argument is copied into the formal argument. (No further connection is really made between the actual and formal arguments.)
All information (data) in your program must at some time reside in memory (except literals). Most of them will be stored 'permanently' (that is for the entire program run) in main's local variables (which will exist until main does -- which is for the entire program execution). But how do they get there and where do they go as the program runs?
Values can be stored in a memory location by input ('cin >> var'), assignment ('var = value'), or initialization ('type var = value' or 'type var(value)'). We don't use initialization a lot (except for constants which cannot be input or assigned). Values can be produced by calculation (a literal is here considered the simplest possible calculation) or entered by the user.
In the triangle program, data flows like this:
main (inches, yards, feet, inches_left, yard_frac) ---------------------------------------- | | || || || || || | | | |i || || || || || | | greeting |n ||y || ||i || || i| goodbye |c i||a i|| i||n i|| i||i n| |h n||r n||y n||c n||f n||n c| |e c||d c||a c||h c||e c||c h| |s h||_ h||r h||e h||e h||h e| | e||f e||d e||s e||t e||e s| read--->---- s||r s||s s||_ s|| s||s | (input) ||a || ||l _|| _||_ y| ||c || ||e l|| l||l a| in2yrd_frac--<---| || ||f e|| e||e r| ---->-- || ||t f|| f||f d| || || t|| t||t s| in2yrd--<---------| || || || | ----->------- || || || f| || || || e| in_rem_yrd--<--------------| || || e| ----->------------ || || t| || || | in2ft--<-------------------| || i| ----->----------------- || n| || c| in_rem_ft--<------------------------| h| ----->---------------------- e| s| _| l| e| f| t| | y| a| r| d| _| f| r| a| c| | ---->---display
In this data flow diagram, we see that main (which has local variables inches, yards, feet, inches_left, and yard_frac) receives inches from read. This value is then sent to in2yrd_frac from whence yard_frac results. inches is then sent into in2yrd giving us back yards. Finally, we send inches into in_rem_yrd to get inches_left. Now inches_left is sent into in2ft to receive feet. Then inches_left is passed into in_rem_ft and the result is stored back into inches_left. All of these variables' values are sent into display for...well...display.
Note also that greeting and goodbye are listed but have no input or output. In addition, display has no output and read has no input. read does, however, have its own local variable -- input.
A more complete diagram would also show how information flows to and from even library functions (like labs and cin's >>). This is often ignored to avoid clutter, however.
A library actually consists of two files: an interface (or header) file and an implementation file. The interface has a .h extension (recall that the standard library once used .h on their files, too; programmer-defined libraries still use .h by convention). The implementation will have a .C extension (since it will hold C++ source code).
The interface contains all constants and prototypes to be made accessible by the library. It will also have three preprocessor directives meant to avoid the circular inclusion of libraries from each other. In general, for a library called lib, you would have an interface file called lib.h which would look like this:
#ifndef LIB_H_INC #define LIB_H_INC // constants and prototypes #endif
Note how the first two lines contain a word (symbol) starting with the name of the library (in all caps).
The implementation file will contain the definitions of all those functions prototyped in the interface file. It might also be using any constants defined in the header, and so should include it. If any standard library functions are used, you can include those, too. A library named lib would have an implementation file called lib.C which would look like this:
#include "lib.h" #include <std___> using namespace std; // define functions prototyped in lib.h
Note how the library's interface file is placed in double quotes instead of the angle brackets we normally use for a #include directive. This tells the compiler to look first in the current directory for the .h file and later to look in the system directories if it can't find it here. This is how we distinguish our own (or local) libraries.
You can use your own library just as you did the standard libraries. Simply include your library's interface file (the .h file). Remember to surround the .h name with double quotes instead of angle brackets! Once that's done, you can call any of the functions provided in that library or use any constants defined in it.
Compiling with a standard library is nothing: it is automatic. But compiling with a local library (one you've written) is a bit more. You'll have to tell the compiler to compile not only the main application (the program or .C file with the main function in it) but also the library's implementation file (the .C file for the library). Just mention both files' names (their .C extensions aren't needed -- nor is the .h file) on the compile line:
CPP program lib
Would compile the files program.C and lib.C and combine all the code into an executable named program.out.
Normally you would give those wanting to use your library the interface file and a binary version of the implemenation file. That is a slightly more advanced topic, however, and will be covered later in CSC217 (assembly language). For now, you'll have to suffer with a source publication of your library. (This is becoming more and more common with Open Source and Java being so widespread.)