Previous: 6.2 Passing Pointers to Functions
Up: 6 Pointers
Next: 6.4 Common Errors
Previous Page: 6.2.3 A function to Swap Values
Next Page: 6.4 Common Errors
We will now modify our pay calculation program so that the driver calls upon other functions to perform all subtasks. The driver, main(), represents only the overall logic of the program; the details are hidden in the functions that perform the various subtasks. The algorithm for the driver is:
get data
repeat the following while there is more data
calculate pay
print data and results
get data
For each step of the algorithm,
we will use functions to do the tasks of getting data, printing
data and results, and calculating pay. We have already written functions in
Chapters Before we write these functions, we should design them by describing what the functions do and specifying the interface to these functions; i.e. by indicating the arguments and their types to be passed to the functions (the information given to the functions) and the meaning and type of the return values (the information returned from the function). Here are our choices:
int get_data(int * pid, float * phrs, float * prate);We use names pid, phrs, and prate, to indicate that they are pointers to cells for the id, hours and rate, respectively. It is a good habit to distinguish between object names and pointer names whenever there is a possibility of confusion.
void print_data(int id, float hrs, float rate, float pay);
void print_pay(float regular, float overtime, float total);
float calc_pay(float hours, float rate, float * pregular,
float * povertime);
Here, pregular and povertime are pointers to cells for
regular and overtime pay objects in
the calling function.
All of these functions will be defined in a file,
payutil.c and their prototypes are included in
payutil.h.
Figure 6.23 shows the header file.
We have also included the definitions for symbolic constants REG_LIMIT and OT_FACTOR in the header file. This header file will be included in all relevant source files.
With the information in this file (and the preceding discussion of the function) we have sufficient information to write the driver for the program using the functions prior to writing the actual code for them. Figure 6.24 shows the driver. It also includes the file, tfdef.h which defines the macros, TRUE and FALSE.
The logic of the driver is as follows. After the program title is printed, the first statement calls get_data() to get the id_number, hours_worked, and rate_of_pay. As indicated in the prototype, pointers to these objects are passed as arguments so that get_data() can indirectly access them and store values. The function, get_data(), returns True or False depending on whether there is new data. The True/False value is assigned to the variable, moredata. The while loop is executed as long as there is more data; i.e. moredata is True. The loop body calls on calc_pay() to calculate the pay, print_data() to print the input data, print_pay() to print the results, and get_data() again to get more data. Since calc_pay() returns the values of overtime and total pay indirectly, main() passes pointers to objects which will hold these values.
The overall logic in the driver is easy to read and understand; at this top level of logic, the details of the computations are not important and would only complicate understanding the program. The driver will remain the same no matter how the various functions are defined. The actual details in one or more functions may be changed at a later time without disturbing the driver or the other functions. This program is implemented in functional modules. Such a modular programming style makes program development, debugging and maintenance much easier.
Of course, we still have to write the various functions used in the above driver. We write each of these functions in turn. Figure 6.25 shows the code for print_data() and print_pay() in the file payutil.c which are simple enough.
The next two functions require indirect access.
The function, calc_pay(), must indirectly
store the regular and overtime pay so the formal parameters include
two pointers: preg (pointing to the cell for regular pay)
and pover (pointing to the cell for overtime pay).
The function returns the value of the total pay.
It is shown in Figure 6.26.
Finally, get_data() must indirectly store the values of the
id number, hours worked, and rate of pay,
and return True if id number is positive, and
False otherwise. Figure 6.27 shows the code.
The formal parameters pid, phrs, and prate are pointers to objects in the calling function ( main() in our case). Recall, when scanf() is called to read data, it requires arguments that are pointers to the objects where the data is to be placed so that it can indirectly store the values. Therefore, when get_data() calls scanf(), it must pass pointers to relevant objects as arguments, i.e. it passes the pointers, pid, phrs, and prate. These pointer variables point to the objects where values are to be stored. We do NOT want to pass &pid, &phrs, &prate as these are the addresses of the pointers, pid, phrs, and prate; they are NOT the addresses cells to hold the data. If the id number stored in *pid is not positive, i.e. (*pid <= 0), get_data() returns FALSE to indicate that there is no more data. If *pid is positive, the rest of the function is executed, in which case the rest of the input data is read. The value, TRUE is returned to indicate that more data is present.
The above functions are in the source file, payutil.c which must be compiled and linked with the source program file, pay6.c. A sample session would be similar to the ones for similar previous programs and is not shown here.