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

6.3 Returning to the Payroll Task with Pointers

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 and to calculate pay and to print data and results, and will repeat them here for easy reference, making some modifications and improvements. We have postponed until now writing a function to read data as such a function would require returning more than one value. By using pointers, we now have the tool at our disposal to implement such a function.

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:

get_data():
This function reads the id number, hours worked, and rate of pay for one employee and stores their values indirectly using pointers. Since these values are returned indirectly, the arguments must be pointers to appropriate objects in the calling function ( main() in our case). The function returns True, if it found new data in the input; it returns False otherwise. Here is the prototype:
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.

print_data():
This function writes the id number, hours worked, and rate of pay passed to it. It has no useful information to return so returns a void type. Here is the prototype:
void print_data(int id, float hrs, float rate, float pay);

print_pay():
This function is given values for the regular pay, overtime pay, and total pay and writes them to the output. It also returns a void type.
void print_pay(float regular, float overtime, float total);

calc_pay():
Given the necessary information (hours and rate), this function calculates and returns the total pay, and indirectly returns the regular and overtime pay. In addition to the values of hours worked and rate of pay, pointers to regular pay and overtime pay are passed to the function. The prototype is:
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.



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

tep@wiliki.eng.hawaii.edu
Wed Aug 17 08:45:54 HST 1994